From python-checkins at python.org Sat Oct 1 01:25:23 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 01 Oct 2016 05:25:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI3ODk3?= =?utf-8?q?=3A_Fixed_possible_crash_in_sqlite3=2EConnection=2Ecreate=5Fcol?= =?utf-8?q?lation=28=29?= Message-ID: <20161001052523.85797.92929.1884AD2A@psf.io> https://hg.python.org/cpython/rev/38e954a2a37e changeset: 104212:38e954a2a37e branch: 2.7 parent: 104187:ce57a74b5223 user: Serhiy Storchaka date: Sat Oct 01 08:24:55 2016 +0300 summary: Issue #27897: Fixed possible crash in sqlite3.Connection.create_collation() if pass invalid string-like object as a name. Original patch by Xiang Zhang. files: Misc/NEWS | 3 +++ Modules/_sqlite/connection.c | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,9 @@ Library ------- +- Issue #27897: Fixed possible crash in sqlite3.Connection.create_collation() + if pass invalid string-like object as a name. Original patch by Xiang Zhang. + - Issue #1703178: Fix the ability to pass the --link-objects option to the distutils build_ext command. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1476,16 +1476,18 @@ goto finally; } - if (!PyArg_ParseTuple(args, "O!O:create_collation(name, callback)", &PyString_Type, &name, &callable)) { + if (!PyArg_ParseTuple(args, "SO:create_collation(name, callback)", + &name, &callable)) { goto finally; } - uppercase_name = PyObject_CallMethod(name, "upper", ""); + uppercase_name = PyObject_CallMethod((PyObject *)&PyString_Type, + "upper", "O", name); if (!uppercase_name) { goto finally; } - chk = PyString_AsString(uppercase_name); + chk = PyString_AS_STRING(uppercase_name); while (*chk) { if ((*chk >= '0' && *chk <= '9') || (*chk >= 'A' && *chk <= 'Z') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 01:48:08 2016 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Oct 2016 05:48:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321085=3A_add_conf?= =?utf-8?q?igure_check_for_siginfo=5Ft=2Esi=5Fband?= Message-ID: <20161001054808.85673.65053.B9701F6E@psf.io> https://hg.python.org/cpython/rev/6874928eae4b changeset: 104213:6874928eae4b parent: 104211:35b5f4cc08f4 user: Zachary Ware date: Sat Oct 01 00:47:27 2016 -0500 summary: Issue #21085: add configure check for siginfo_t.si_band Patch by Masayuki Yamamoto, reviewed and rebased by Erik Bray. This is a first step on the long road toward resupporting Cygwin, which does not provide siginfo_t.si_band. files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/signalmodule.c | 4 ++++ configure | 12 ++++++++++++ configure.ac | 2 ++ pyconfig.h.in | 3 +++ 6 files changed, 25 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1671,6 +1671,7 @@ Arnon Yaari Alakshendra Yadav Hirokazu Yamamoto +Masayuki Yamamoto Ka-Ping Yee Chi Hsuan Yen Jason Yeo diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -173,6 +173,9 @@ Build ----- +- Issue #21085: Add configure check for siginfo_t.si_band, which Cygwin does + not provide. Patch by Masayuki Yamamoto with review and rebase by Erik Bray. + - Issue #28258: Fixed build with Estonian locale (python-config and distclean targets in Makefile). Patch by Arfrever Frehtes Taifersar Arahesis. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -957,7 +957,11 @@ PyStructSequence_SET_ITEM(result, 4, _PyLong_FromUid(si->si_uid)); PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong((long)(si->si_status))); +#ifdef HAVE_SIGINFO_T_SI_BAND PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(si->si_band)); +#else + PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(0L)); +#endif if (PyErr_Occurred()) { Py_DECREF(result); return NULL; diff --git a/configure b/configure --- a/configure +++ b/configure @@ -13089,6 +13089,18 @@ fi +# Issue #21085: In Cygwin, siginfo_t does not have si_band field. +ac_fn_c_check_member "$LINENO" "siginfo_t" "si_band" "ac_cv_member_siginfo_t_si_band" "#include +" +if test "x$ac_cv_member_siginfo_t_si_band" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_SIGINFO_T_SI_BAND 1 +_ACEOF + + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 $as_echo_n "checking for time.h that defines altzone... " >&6; } diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3907,6 +3907,8 @@ #include #include ]]) ++# Issue #21085: In Cygwin, siginfo_t does not have si_band field. ++AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[#include ]]) AC_MSG_CHECKING(for time.h that defines altzone) AC_CACHE_VAL(ac_cv_header_time_altzone,[ diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -856,6 +856,9 @@ /* Define to 1 if you have the `sigaltstack' function. */ #undef HAVE_SIGALTSTACK +/* Define to 1 if `si_band' is a member of `siginfo_t'. */ +#undef HAVE_SIGINFO_T_SI_BAND + /* Define to 1 if you have the `siginterrupt' function. */ #undef HAVE_SIGINTERRUPT -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 02:07:02 2016 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Oct 2016 06:07:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321085=3A_Fix_acci?= =?utf-8?q?dental_leading_+=27s_in_configure=2Eac?= Message-ID: <20161001060701.1465.55438.75D3C900@psf.io> https://hg.python.org/cpython/rev/5673cf852daa changeset: 104214:5673cf852daa user: Zachary Ware date: Sat Oct 01 01:06:51 2016 -0500 summary: Issue #21085: Fix accidental leading +'s in configure.ac files: configure.ac | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3907,8 +3907,8 @@ #include #include ]]) -+# Issue #21085: In Cygwin, siginfo_t does not have si_band field. -+AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[#include ]]) +# Issue #21085: In Cygwin, siginfo_t does not have si_band field. +AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[#include ]]) AC_MSG_CHECKING(for time.h that defines altzone) AC_CACHE_VAL(ac_cv_header_time_altzone,[ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 17:15:19 2016 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Oct 2016 21:15:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313756=3A_Fix_buil?= =?utf-8?q?ding_extensions_modules_on_Cygwin?= Message-ID: <20161001211519.79489.3881.69D1C47E@psf.io> https://hg.python.org/cpython/rev/5b4c21436036 changeset: 104215:5b4c21436036 user: Zachary Ware date: Sat Oct 01 16:15:09 2016 -0500 summary: Issue #13756: Fix building extensions modules on Cygwin Patch by Roumen Petrov, based on original patch by Jason Tishler. files: Lib/distutils/command/build_ext.py | 7 ------- Makefile.pre.in | 2 +- Misc/NEWS | 3 +++ Modules/makesetup | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -715,13 +715,6 @@ return ext.libraries + [pythonlib] else: return ext.libraries - elif sys.platform[:6] == "cygwin": - template = "python%d.%d" - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - # don't extend ext.libraries, it may be shared with other - # extensions, it is a reference to the original list - return ext.libraries + [pythonlib] elif sys.platform[:6] == "atheos": from distutils import sysconfig diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -674,7 +674,7 @@ # This rule builds the Cygwin Python DLL and import library if configured # for a shared core library; otherwise, this rule is a noop. -$(DLLLIBRARY) libpython$(VERSION).dll.a: $(LIBRARY_OBJS) +$(DLLLIBRARY) libpython$(LDVERSION).dll.a: $(LIBRARY_OBJS) if test -n "$(DLLLIBRARY)"; then \ $(LDSHARED) -Wl,--out-implib=$@ -o $(DLLLIBRARY) $^ \ $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST); \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -173,6 +173,9 @@ Build ----- +- Issue #13756: Fix building extensions modules on Cygwin. Patch by Roumen + Petrov, based on original patch by Jason Tishler. + - Issue #21085: Add configure check for siginfo_t.si_band, which Cygwin does not provide. Patch by Masayuki Yamamoto with review and rebase by Erik Bray. diff --git a/Modules/makesetup b/Modules/makesetup --- a/Modules/makesetup +++ b/Modules/makesetup @@ -91,7 +91,7 @@ else ExtraLibDir='$(LIBPL)' fi - ExtraLibs="-L$ExtraLibDir -lpython\$(VERSION)";; + ExtraLibs="-L$ExtraLibDir -lpython\$(LDVERSION)";; esac # Main loop -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 18:01:30 2016 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Oct 2016 22:01:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogVXBkYXRlIC57aGcsZ2l0fWln?= =?utf-8?q?nore_for_Cygwin_builds?= Message-ID: <20161001220130.5201.47113.B31FE7F6@psf.io> https://hg.python.org/cpython/rev/c2c147bb811a changeset: 104216:c2c147bb811a user: Zachary Ware date: Sat Oct 01 17:00:51 2016 -0500 summary: Update .{hg,git}ignore for Cygwin builds files: .gitignore | 4 ++++ .hgignore | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,10 @@ Modules/config.c Modules/ld_so_aix Programs/_freeze_importlib +Programs/_freeze_importlib.exe Programs/_testembed +Programs/_testembed.exe +Programs/pgen.exe PC/python_nt*.h PC/pythonnt_rc*.h PC/*/*.exe @@ -72,6 +75,7 @@ libpython*.a libpython*.so* libpython*.dylib +libpython*.dll platform pybuilddir.txt pyconfig.h diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -44,6 +44,7 @@ libpython*.a libpython*.so* libpython*.dylib +libpython*.dll *.swp *.o *.pyc @@ -87,8 +88,9 @@ Tools/unicode/MAPPINGS/ BuildLog.htm __pycache__ -Programs/_freeze_importlib -Programs/_testembed +Programs/_freeze_importlib{,.exe} +Programs/_testembed{,.exe} +Programs/pgen.exe .coverage coverage/ externals/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 18:18:13 2016 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Oct 2016 22:18:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_pgen_lives_in_Parser=2C_no?= =?utf-8?q?t_Programs=2E?= Message-ID: <20161001221812.17363.98068.DF752B24@psf.io> https://hg.python.org/cpython/rev/ee71de4287c5 changeset: 104217:ee71de4287c5 user: Zachary Ware date: Sat Oct 01 17:18:03 2016 -0500 summary: pgen lives in Parser, not Programs. Apparently, I can't read. files: .gitignore | 2 +- .hgignore | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ Programs/_freeze_importlib.exe Programs/_testembed Programs/_testembed.exe -Programs/pgen.exe PC/python_nt*.h PC/pythonnt_rc*.h PC/*/*.exe @@ -60,6 +59,7 @@ PCBuild/win32/ .purify Parser/pgen +Parser/pgen.exe __pycache__ autom4te.cache build/ diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -33,7 +33,6 @@ Modules/Setup.local Modules/config.c Modules/ld_so_aix$ -Parser/pgen$ ^lcov-report/ ^core ^python-gdb.py @@ -88,9 +87,9 @@ Tools/unicode/MAPPINGS/ BuildLog.htm __pycache__ +Parser/pgen{,.exe} Programs/_freeze_importlib{,.exe} Programs/_testembed{,.exe} -Programs/pgen.exe .coverage coverage/ externals/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 21:34:02 2016 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Oct 2016 01:34:02 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzIz?= =?utf-8?q?=3A_Remove_vestigal_MacOS_9_checks_from_exit=28=29_and_quit=28?= =?utf-8?b?KS4=?= Message-ID: <20161002013402.20251.34061.03BD0883@psf.io> https://hg.python.org/cpython/rev/2d8d9abb3bf8 changeset: 104218:2d8d9abb3bf8 branch: 3.6 parent: 104210:dca18f0ec280 user: Ned Deily date: Sat Oct 01 21:12:16 2016 -0400 summary: Issue #28323: Remove vestigal MacOS 9 checks from exit() and quit(). Patch by Chi Hsuan Yen. files: Lib/site.py | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -336,9 +336,7 @@ The repr of each object contains a hint at how it works. """ - if os.sep == ':': - eof = 'Cmd-Q' - elif os.sep == '\\': + if os.sep == '\\': eof = 'Ctrl-Z plus Return' else: eof = 'Ctrl-D (i.e. EOF)' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 21:34:02 2016 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Oct 2016 01:34:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328323=3A_Merge_from_3=2E6?= Message-ID: <20161002013402.20873.68746.20E6D287@psf.io> https://hg.python.org/cpython/rev/2c7034d59c7b changeset: 104219:2c7034d59c7b parent: 104217:ee71de4287c5 parent: 104218:2d8d9abb3bf8 user: Ned Deily date: Sat Oct 01 21:21:44 2016 -0400 summary: Issue #28323: Merge from 3.6 files: Lib/site.py | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -336,9 +336,7 @@ The repr of each object contains a hint at how it works. """ - if os.sep == ':': - eof = 'Cmd-Q' - elif os.sep == '\\': + if os.sep == '\\': eof = 'Ctrl-Z plus Return' else: eof = 'Ctrl-D (i.e. EOF)' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 21:34:02 2016 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Oct 2016 01:34:02 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzI0?= =?utf-8?q?=3A_Remove_vestigal_MacOS_9_references_in_os=2Epy_docstring=2E?= Message-ID: <20161002013402.85846.51623.44C88E85@psf.io> https://hg.python.org/cpython/rev/dbdcedf3583e changeset: 104220:dbdcedf3583e branch: 3.6 parent: 104218:2d8d9abb3bf8 user: Ned Deily date: Sat Oct 01 21:12:35 2016 -0400 summary: Issue #28324: Remove vestigal MacOS 9 references in os.py docstring. Patch by Chi Hsuan Yen. files: Lib/os.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -4,9 +4,9 @@ - all functions from posix or nt, e.g. unlink, stat, etc. - os.path is either posixpath or ntpath - os.name is either 'posix' or 'nt' - - os.curdir is a string representing the current directory ('.' or ':') - - os.pardir is a string representing the parent directory ('..' or '::') - - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\') + - os.curdir is a string representing the current directory (always '.') + - os.pardir is a string representing the parent directory (always '..') + - os.sep is the (or a most common) pathname separator ('/' or '\\') - os.extsep is the extension separator (always '.') - os.altsep is the alternate pathname separator (None or '/') - os.pathsep is the component separator used in $PATH etc -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 21:34:03 2016 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Oct 2016 01:34:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328324=3A_Merge_from_3=2E6?= Message-ID: <20161002013402.82059.14255.EFD4B6F0@psf.io> https://hg.python.org/cpython/rev/d55fd379b994 changeset: 104221:d55fd379b994 parent: 104219:2c7034d59c7b parent: 104220:dbdcedf3583e user: Ned Deily date: Sat Oct 01 21:33:34 2016 -0400 summary: Issue #28324: Merge from 3.6 files: Lib/os.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -4,9 +4,9 @@ - all functions from posix or nt, e.g. unlink, stat, etc. - os.path is either posixpath or ntpath - os.name is either 'posix' or 'nt' - - os.curdir is a string representing the current directory ('.' or ':') - - os.pardir is a string representing the parent directory ('..' or '::') - - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\') + - os.curdir is a string representing the current directory (always '.') + - os.pardir is a string representing the parent directory (always '..') + - os.sep is the (or a most common) pathname separator ('/' or '\\') - os.extsep is the extension separator (always '.') - os.altsep is the alternate pathname separator (None or '/') - os.pathsep is the component separator used in $PATH etc -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 1 22:06:06 2016 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Oct 2016 02:06:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328325=3A_Remove_v?= =?utf-8?q?estigal_MacOS_9_macurl2path_module_and_its_tests=2E?= Message-ID: <20161002020606.79450.55306.81E0F97A@psf.io> https://hg.python.org/cpython/rev/07c593845994 changeset: 104222:07c593845994 user: Ned Deily date: Sat Oct 01 22:05:07 2016 -0400 summary: Issue #28325: Remove vestigal MacOS 9 macurl2path module and its tests. files: Lib/macurl2path.py | 77 ------------------------ Lib/test/test_macurl2path.py | 31 --------- Misc/NEWS | 2 + 3 files changed, 2 insertions(+), 108 deletions(-) diff --git a/Lib/macurl2path.py b/Lib/macurl2path.py deleted file mode 100644 --- a/Lib/macurl2path.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Macintosh-specific module for conversion between pathnames and URLs. - -Do not import directly; use urllib instead.""" - -import urllib.parse -import os - -__all__ = ["url2pathname","pathname2url"] - -def url2pathname(pathname): - """OS-specific conversion from a relative URL of the 'file' scheme - to a file system path; not recommended for general use.""" - # - # XXXX The .. handling should be fixed... - # - tp = urllib.parse.splittype(pathname)[0] - if tp and tp != 'file': - raise RuntimeError('Cannot convert non-local URL to pathname') - # Turn starting /// into /, an empty hostname means current host - if pathname[:3] == '///': - pathname = pathname[2:] - elif pathname[:2] == '//': - raise RuntimeError('Cannot convert non-local URL to pathname') - components = pathname.split('/') - # Remove . and embedded .. - i = 0 - while i < len(components): - if components[i] == '.': - del components[i] - elif components[i] == '..' and i > 0 and \ - components[i-1] not in ('', '..'): - del components[i-1:i+1] - i = i-1 - elif components[i] == '' and i > 0 and components[i-1] != '': - del components[i] - else: - i = i+1 - if not components[0]: - # Absolute unix path, don't start with colon - rv = ':'.join(components[1:]) - else: - # relative unix path, start with colon. First replace - # leading .. by empty strings (giving ::file) - i = 0 - while i < len(components) and components[i] == '..': - components[i] = '' - i = i + 1 - rv = ':' + ':'.join(components) - # and finally unquote slashes and other funny characters - return urllib.parse.unquote(rv) - -def pathname2url(pathname): - """OS-specific conversion from a file system path to a relative URL - of the 'file' scheme; not recommended for general use.""" - if '/' in pathname: - raise RuntimeError("Cannot convert pathname containing slashes") - components = pathname.split(':') - # Remove empty first and/or last component - if components[0] == '': - del components[0] - if components[-1] == '': - del components[-1] - # Replace empty string ('::') by .. (will result in '/../' later) - for i in range(len(components)): - if components[i] == '': - components[i] = '..' - # Truncate names longer than 31 bytes - components = map(_pncomp2url, components) - - if os.path.isabs(pathname): - return '/' + '/'.join(components) - else: - return '/'.join(components) - -def _pncomp2url(component): - # We want to quote slashes - return urllib.parse.quote(component[:31], safe='') diff --git a/Lib/test/test_macurl2path.py b/Lib/test/test_macurl2path.py deleted file mode 100644 --- a/Lib/test/test_macurl2path.py +++ /dev/null @@ -1,31 +0,0 @@ -import macurl2path -import unittest - -class MacUrl2PathTestCase(unittest.TestCase): - def test_url2pathname(self): - self.assertEqual(":index.html", macurl2path.url2pathname("index.html")) - self.assertEqual(":bar:index.html", macurl2path.url2pathname("bar/index.html")) - self.assertEqual("foo:bar:index.html", macurl2path.url2pathname("/foo/bar/index.html")) - self.assertEqual("foo:bar", macurl2path.url2pathname("/foo/bar/")) - self.assertEqual("", macurl2path.url2pathname("/")) - self.assertRaises(RuntimeError, macurl2path.url2pathname, "http://foo.com") - self.assertEqual("index.html", macurl2path.url2pathname("///index.html")) - self.assertRaises(RuntimeError, macurl2path.url2pathname, "//index.html") - self.assertEqual(":index.html", macurl2path.url2pathname("./index.html")) - self.assertEqual(":index.html", macurl2path.url2pathname("foo/../index.html")) - self.assertEqual("::index.html", macurl2path.url2pathname("../index.html")) - - def test_pathname2url(self): - self.assertEqual("drive", macurl2path.pathname2url("drive:")) - self.assertEqual("drive/dir", macurl2path.pathname2url("drive:dir:")) - self.assertEqual("drive/dir/file", macurl2path.pathname2url("drive:dir:file")) - self.assertEqual("drive/file", macurl2path.pathname2url("drive:file")) - self.assertEqual("file", macurl2path.pathname2url("file")) - self.assertEqual("file", macurl2path.pathname2url(":file")) - self.assertEqual("dir", macurl2path.pathname2url(":dir:")) - self.assertEqual("dir/file", macurl2path.pathname2url(":dir:file")) - self.assertRaises(RuntimeError, macurl2path.pathname2url, "/") - self.assertEqual("dir/../file", macurl2path.pathname2url("dir::file")) - -if __name__ == "__main__": - unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -148,6 +148,8 @@ - Issue #27759: Fix selectors incorrectly retain invalid file descriptors. Patch by Mark Williams. +- Issue #28325: Remove vestigal MacOS 9 macurl2path module and its tests. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 01:34:09 2016 From: python-checkins at python.org (zach.ware) Date: Sun, 02 Oct 2016 05:34:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321124=3A_Fix_buil?= =?utf-8?q?ding_=5Fstruct_on_Cygwin=2E?= Message-ID: <20161002053409.15189.96128.EF708AA1@psf.io> https://hg.python.org/cpython/rev/3bde312ae936 changeset: 104223:3bde312ae936 user: Zachary Ware date: Sun Oct 02 00:33:39 2016 -0500 summary: Issue #21124: Fix building _struct on Cygwin. Patch by Masayuki Yamamoto. files: Misc/NEWS | 4 ++++ Modules/_struct.c | 2 +- 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -175,6 +175,10 @@ Build ----- +- Issue #21124: Fix building the _struct module on Cygwin by passing ``NULL`` + instead of ``&PyType_Type`` to PyVarObject_HEAD_INIT. Patch by Masayuki + Yamamoto. + - Issue #13756: Fix building extensions modules on Cygwin. Patch by Roumen Petrov, based on original patch by Jason Tishler. diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1650,7 +1650,7 @@ } static PyTypeObject unpackiter_type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(NULL, 0) "unpack_iterator", /* tp_name */ sizeof(unpackiterobject), /* tp_basicsize */ 0, /* tp_itemsize */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 02:17:29 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 06:17:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328322=3A_Fixed_possible_crashes_when_unpickle_i?= =?utf-8?q?tertools_objects_from?= Message-ID: <20161002061729.17369.62600.14043804@psf.io> https://hg.python.org/cpython/rev/cb0755aa9f3d changeset: 104226:cb0755aa9f3d parent: 104223:3bde312ae936 parent: 104225:c4937d066a8e user: Serhiy Storchaka date: Sun Oct 02 09:17:08 2016 +0300 summary: Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. files: Lib/test/test_itertools.py | 24 +++++++++++++-- Misc/NEWS | 3 + Modules/itertoolsmodule.c | 40 ++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -183,6 +183,19 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, chain('abc', 'def'), compare=list('abcdef')) + def test_chain_setstate(self): + self.assertRaises(TypeError, chain().__setstate__, ()) + self.assertRaises(TypeError, chain().__setstate__, []) + self.assertRaises(TypeError, chain().__setstate__, 0) + self.assertRaises(TypeError, chain().__setstate__, ([],)) + self.assertRaises(TypeError, chain().__setstate__, (iter([]), [])) + it = chain() + it.__setstate__((iter(['abc', 'def']),)) + self.assertEqual(list(it), ['a', 'b', 'c', 'd', 'e', 'f']) + it = chain() + it.__setstate__((iter(['abc', 'def']), iter(['ghi']))) + self.assertEqual(list(it), ['ghi', 'a', 'b', 'c', 'd', 'e', 'f']) + def test_combinations(self): self.assertRaises(TypeError, combinations, 'abc') # missing r argument self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments @@ -667,19 +680,22 @@ self.assertEqual(take(20, c), list('defgabcdefgabcdefgab')) # The first argument to setstate needs to be a tuple - with self.assertRaises(SystemError): + with self.assertRaises(TypeError): cycle('defg').__setstate__([list('abcdefg'), 0]) # The first argument in the setstate tuple must be a list with self.assertRaises(TypeError): c = cycle('defg') - c.__setstate__((dict.fromkeys('defg'), 0)) - take(20, c) + c.__setstate__((tuple('defg'), 0)) + take(20, c) - # The first argument in the setstate tuple must be a list + # The second argument in the setstate tuple must be an int with self.assertRaises(TypeError): cycle('defg').__setstate__((list('abcdefg'), 'x')) + self.assertRaises(TypeError, cycle('').__setstate__, ()) + self.assertRaises(TypeError, cycle('').__setstate__, ([],)) + def test_groupby(self): # Check whether it accepts arguments correctly self.assertEqual([], list(groupby([]))) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,9 @@ Library ------- +- Issue #28322: Fixed possible crashes when unpickle itertools objects from + incorrect pickle data. Based on patch by John Leitch. + - Issue #28228: imghdr now supports pathlib. - Issue #28226: compileall now supports pathlib. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -147,8 +147,13 @@ groupby_setstate(groupbyobject *lz, PyObject *state) { PyObject *currkey, *currvalue, *tgtkey; - if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) { + return NULL; + } Py_INCREF(currkey); Py_XSETREF(lz->currkey, currkey); Py_INCREF(currvalue); @@ -727,8 +732,13 @@ { teedataobject *tdo; int index; - if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) { + return NULL; + } if (index < 0 || index > LINKCELLS) { PyErr_SetString(PyExc_ValueError, "Index out of range"); return NULL; @@ -971,9 +981,13 @@ { PyObject *saved=NULL; int firstpass; - - if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) { + return NULL; + } Py_INCREF(saved); Py_XSETREF(lz->saved, saved); lz->firstpass = firstpass != 0; @@ -1903,8 +1917,17 @@ { PyObject *source, *active=NULL; - if (! PyArg_ParseTuple(state, "O|O", &source, &active)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O|O", &source, &active)) { + return NULL; + } + if (!PyIter_Check(source) || (active != NULL && !PyIter_Check(active))) { + PyErr_SetString(PyExc_TypeError, "Arguments must be iterators."); + return NULL; + } Py_INCREF(source); Py_XSETREF(lz->source, source); @@ -3262,10 +3285,15 @@ PyObject *indices, *cycles, *result; Py_ssize_t n, i; + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); + return NULL; + } if (!PyArg_ParseTuple(state, "O!O!", &PyTuple_Type, &indices, - &PyTuple_Type, &cycles)) + &PyTuple_Type, &cycles)) { return NULL; + } n = PyTuple_GET_SIZE(po->pool); if (PyTuple_GET_SIZE(indices) != n || PyTuple_GET_SIZE(cycles) != po->r) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 02:17:29 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 06:17:29 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzIy?= =?utf-8?q?=3A_Fixed_possible_crashes_when_unpickle_itertools_objects_from?= Message-ID: <20161002061729.1717.19859.1961A452@psf.io> https://hg.python.org/cpython/rev/258ebc539b2e changeset: 104224:258ebc539b2e branch: 3.5 parent: 104209:36d37ff6c236 user: Serhiy Storchaka date: Sun Oct 02 08:34:53 2016 +0300 summary: Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. files: Lib/test/test_itertools.py | 32 ++++++++++++++++++++ Misc/NEWS | 3 + Modules/itertoolsmodule.c | 40 ++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -184,6 +184,19 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, chain('abc', 'def'), compare=list('abcdef')) + def test_chain_setstate(self): + self.assertRaises(TypeError, chain().__setstate__, ()) + self.assertRaises(TypeError, chain().__setstate__, []) + self.assertRaises(TypeError, chain().__setstate__, 0) + self.assertRaises(TypeError, chain().__setstate__, ([],)) + self.assertRaises(TypeError, chain().__setstate__, (iter([]), [])) + it = chain() + it.__setstate__((iter(['abc', 'def']),)) + self.assertEqual(list(it), ['a', 'b', 'c', 'd', 'e', 'f']) + it = chain() + it.__setstate__((iter(['abc', 'def']), iter(['ghi']))) + self.assertEqual(list(it), ['ghi', 'a', 'b', 'c', 'd', 'e', 'f']) + def test_combinations(self): self.assertRaises(TypeError, combinations, 'abc') # missing r argument self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments @@ -631,6 +644,25 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, cycle('abc')) + def test_cycle_setstate(self): + self.assertRaises(TypeError, cycle('').__setstate__, ()) + self.assertRaises(TypeError, cycle('').__setstate__, []) + self.assertRaises(TypeError, cycle('').__setstate__, 0) + self.assertRaises(TypeError, cycle('').__setstate__, ([],)) + self.assertRaises(TypeError, cycle('').__setstate__, ((), 0)) + it = cycle('abc') + it.__setstate__((['de', 'fg'], 0)) + self.assertEqual(list(islice(it, 15)), + ['a', 'b', 'c', 'de', 'fg', + 'a', 'b', 'c', 'de', 'fg', + 'a', 'b', 'c', 'de', 'fg']) + it = cycle('abc') + it.__setstate__((['de', 'fg'], 1)) + self.assertEqual(list(islice(it, 15)), + ['a', 'b', 'c', 'de', 'fg', + 'de', 'fg', 'de', 'fg', 'de', + 'fg', 'de', 'fg', 'de', 'fg']) + def test_groupby(self): # Check whether it accepts arguments correctly self.assertEqual([], list(groupby([]))) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,9 @@ Library ------- +- Issue #28322: Fixed possible crashes when unpickle itertools objects from + incorrect pickle data. Based on patch by John Leitch. + - Issue #1703178: Fix the ability to pass the --link-objects option to the distutils build_ext command. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -155,8 +155,13 @@ groupby_setstate(groupbyobject *lz, PyObject *state) { PyObject *currkey, *currvalue, *tgtkey; - if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) { + return NULL; + } Py_INCREF(currkey); Py_XSETREF(lz->currkey, currkey); Py_INCREF(currvalue); @@ -736,8 +741,13 @@ { teedataobject *tdo; int index; - if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) { + return NULL; + } if (index < 0 || index > LINKCELLS) { PyErr_SetString(PyExc_ValueError, "Index out of range"); return NULL; @@ -966,8 +976,13 @@ { PyObject *saved=NULL; int firstpass; - if (!PyArg_ParseTuple(state, "Oi", &saved, &firstpass)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) { + return NULL; + } Py_XINCREF(saved); Py_XSETREF(lz->saved, saved); lz->firstpass = firstpass != 0; @@ -1891,8 +1906,18 @@ chain_setstate(chainobject *lz, PyObject *state) { PyObject *source, *active=NULL; - if (! PyArg_ParseTuple(state, "O|O", &source, &active)) + + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O|O", &source, &active)) { + return NULL; + } + if (!PyIter_Check(source) || (active != NULL && !PyIter_Check(active))) { + PyErr_SetString(PyExc_TypeError, "Arguments must be iterators."); + return NULL; + } Py_INCREF(source); Py_XSETREF(lz->source, source); @@ -3251,10 +3276,15 @@ PyObject *indices, *cycles, *result; Py_ssize_t n, i; + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); + return NULL; + } if (!PyArg_ParseTuple(state, "O!O!", &PyTuple_Type, &indices, - &PyTuple_Type, &cycles)) + &PyTuple_Type, &cycles)) { return NULL; + } n = PyTuple_GET_SIZE(po->pool); if (PyTuple_GET_SIZE(indices) != n || -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 02:17:29 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 06:17:29 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328322=3A_Fixed_possible_crashes_when_unpickle_itertoo?= =?utf-8?q?ls_objects_from?= Message-ID: <20161002061729.17336.35475.1E030948@psf.io> https://hg.python.org/cpython/rev/c4937d066a8e changeset: 104225:c4937d066a8e branch: 3.6 parent: 104220:dbdcedf3583e parent: 104224:258ebc539b2e user: Serhiy Storchaka date: Sun Oct 02 09:13:14 2016 +0300 summary: Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. files: Lib/test/test_itertools.py | 24 +++++++++++++-- Misc/NEWS | 3 + Modules/itertoolsmodule.c | 40 ++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -183,6 +183,19 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, chain('abc', 'def'), compare=list('abcdef')) + def test_chain_setstate(self): + self.assertRaises(TypeError, chain().__setstate__, ()) + self.assertRaises(TypeError, chain().__setstate__, []) + self.assertRaises(TypeError, chain().__setstate__, 0) + self.assertRaises(TypeError, chain().__setstate__, ([],)) + self.assertRaises(TypeError, chain().__setstate__, (iter([]), [])) + it = chain() + it.__setstate__((iter(['abc', 'def']),)) + self.assertEqual(list(it), ['a', 'b', 'c', 'd', 'e', 'f']) + it = chain() + it.__setstate__((iter(['abc', 'def']), iter(['ghi']))) + self.assertEqual(list(it), ['ghi', 'a', 'b', 'c', 'd', 'e', 'f']) + def test_combinations(self): self.assertRaises(TypeError, combinations, 'abc') # missing r argument self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments @@ -667,19 +680,22 @@ self.assertEqual(take(20, c), list('defgabcdefgabcdefgab')) # The first argument to setstate needs to be a tuple - with self.assertRaises(SystemError): + with self.assertRaises(TypeError): cycle('defg').__setstate__([list('abcdefg'), 0]) # The first argument in the setstate tuple must be a list with self.assertRaises(TypeError): c = cycle('defg') - c.__setstate__((dict.fromkeys('defg'), 0)) - take(20, c) + c.__setstate__((tuple('defg'), 0)) + take(20, c) - # The first argument in the setstate tuple must be a list + # The second argument in the setstate tuple must be an int with self.assertRaises(TypeError): cycle('defg').__setstate__((list('abcdefg'), 'x')) + self.assertRaises(TypeError, cycle('').__setstate__, ()) + self.assertRaises(TypeError, cycle('').__setstate__, ([],)) + def test_groupby(self): # Check whether it accepts arguments correctly self.assertEqual([], list(groupby([]))) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,9 @@ Library ------- +- Issue #28322: Fixed possible crashes when unpickle itertools objects from + incorrect pickle data. Based on patch by John Leitch. + - Issue #28228: imghdr now supports pathlib. - Issue #28226: compileall now supports pathlib. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -147,8 +147,13 @@ groupby_setstate(groupbyobject *lz, PyObject *state) { PyObject *currkey, *currvalue, *tgtkey; - if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) { + return NULL; + } Py_INCREF(currkey); Py_XSETREF(lz->currkey, currkey); Py_INCREF(currvalue); @@ -727,8 +732,13 @@ { teedataobject *tdo; int index; - if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) { + return NULL; + } if (index < 0 || index > LINKCELLS) { PyErr_SetString(PyExc_ValueError, "Index out of range"); return NULL; @@ -971,9 +981,13 @@ { PyObject *saved=NULL; int firstpass; - - if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) { + return NULL; + } Py_INCREF(saved); Py_XSETREF(lz->saved, saved); lz->firstpass = firstpass != 0; @@ -1903,8 +1917,17 @@ { PyObject *source, *active=NULL; - if (! PyArg_ParseTuple(state, "O|O", &source, &active)) + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; + } + if (!PyArg_ParseTuple(state, "O|O", &source, &active)) { + return NULL; + } + if (!PyIter_Check(source) || (active != NULL && !PyIter_Check(active))) { + PyErr_SetString(PyExc_TypeError, "Arguments must be iterators."); + return NULL; + } Py_INCREF(source); Py_XSETREF(lz->source, source); @@ -3262,10 +3285,15 @@ PyObject *indices, *cycles, *result; Py_ssize_t n, i; + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a tuple"); + return NULL; + } if (!PyArg_ParseTuple(state, "O!O!", &PyTuple_Type, &indices, - &PyTuple_Type, &cycles)) + &PyTuple_Type, &cycles)) { return NULL; + } n = PyTuple_GET_SIZE(po->pool); if (PyTuple_GET_SIZE(indices) != n || PyTuple_GET_SIZE(cycles) != po->r) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 03:38:23 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 07:38:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4MjU3?= =?utf-8?q?=3A_Backported_a_test=2E?= Message-ID: <20161002073814.20766.97683.0E62BF3E@psf.io> https://hg.python.org/cpython/rev/a8168a52a56f changeset: 104230:a8168a52a56f branch: 2.7 parent: 104212:38e954a2a37e user: Serhiy Storchaka date: Sun Oct 02 10:36:33 2016 +0300 summary: Issue #28257: Backported a test. files: Lib/test/test_extcall.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -180,6 +180,11 @@ ... TypeError: h() argument after * must be an iterable, not function + >>> h(1, *h) + Traceback (most recent call last): + ... + TypeError: h() argument after * must be an iterable, not function + >>> dir(*h) Traceback (most recent call last): ... -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 03:38:23 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 07:38:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Null_merge?= Message-ID: <20161002073814.17526.36264.3FCD7177@psf.io> https://hg.python.org/cpython/rev/d619246e5eb7 changeset: 104231:d619246e5eb7 branch: 3.6 parent: 104227:88b319dfc909 parent: 104229:40d7ce58ebd0 user: Serhiy Storchaka date: Sun Oct 02 10:37:43 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 03:38:26 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 07:38:26 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MjU3?= =?utf-8?q?=3A_Backported_a_test=2E?= Message-ID: <20161002073814.82256.46449.F4663E1C@psf.io> https://hg.python.org/cpython/rev/40d7ce58ebd0 changeset: 104229:40d7ce58ebd0 branch: 3.5 parent: 104224:258ebc539b2e user: Serhiy Storchaka date: Sun Oct 02 10:36:33 2016 +0300 summary: Issue #28257: Backported a test. files: Lib/test/test_extcall.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -233,6 +233,11 @@ ... TypeError: h() argument after * must be an iterable, not function + >>> h(1, *h) + Traceback (most recent call last): + ... + TypeError: h() argument after * must be an iterable, not function + >>> dir(*h) Traceback (most recent call last): ... -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 03:38:26 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 07:38:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328257=3A_Improved_error_message_when_pass_a_non?= =?utf-8?q?-iterable_as?= Message-ID: <20161002073814.20849.77488.DC8726D4@psf.io> https://hg.python.org/cpython/rev/bde594cd8369 changeset: 104228:bde594cd8369 parent: 104226:cb0755aa9f3d parent: 104227:88b319dfc909 user: Serhiy Storchaka date: Sun Oct 02 10:34:46 2016 +0300 summary: Issue #28257: Improved error message when pass a non-iterable as a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL. files: Include/opcode.h | 1 + Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 5 +- Lib/test/test_extcall.py | 10 + Misc/NEWS | 3 + Python/ceval.c | 13 +- Python/compile.c | 4 +- Python/importlib_external.h | 212 +++++++------- Python/opcode_targets.h | 2 +- 9 files changed, 140 insertions(+), 113 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h --- a/Include/opcode.h +++ b/Include/opcode.h @@ -125,6 +125,7 @@ #define FORMAT_VALUE 155 #define BUILD_CONST_KEY_MAP 156 #define BUILD_STRING 157 +#define BUILD_TUPLE_UNPACK_WITH_CALL 158 /* EXCEPT_HANDLER is a special, implicit block type which is created when entering an except handler. It is not an opcode but we define it here diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -238,6 +238,7 @@ # #27985) # Python 3.6b1 3376 (simplify CALL_FUNCTIONs & BUILD_MAP_UNPACK_WITH_CALL) # Python 3.6b1 3377 (set __class__ cell from type.__new__ #23722) +# Python 3.6b2 3378 (add BUILD_TUPLE_UNPACK_WITH_CALL #28257) # # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually @@ -246,7 +247,7 @@ # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3377).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3378).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -196,8 +196,6 @@ def_op('LOAD_CLASSDEREF', 148) hasfree.append(148) -jrel_op('SETUP_ASYNC_WITH', 154) - def_op('EXTENDED_ARG', 144) EXTENDED_ARG = 144 @@ -207,8 +205,11 @@ def_op('BUILD_TUPLE_UNPACK', 152) def_op('BUILD_SET_UNPACK', 153) +jrel_op('SETUP_ASYNC_WITH', 154) + def_op('FORMAT_VALUE', 155) def_op('BUILD_CONST_KEY_MAP', 156) def_op('BUILD_STRING', 157) +def_op('BUILD_TUPLE_UNPACK_WITH_CALL', 158) del def_op, name_op, jrel_op, jabs_op diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -233,6 +233,16 @@ ... TypeError: h() argument after * must be an iterable, not function + >>> h(1, *h) + Traceback (most recent call last): + ... + TypeError: h() argument after * must be an iterable, not function + + >>> h(*[1], *h) + Traceback (most recent call last): + ... + TypeError: h() argument after * must be an iterable, not function + >>> dir(*h) Traceback (most recent call last): ... diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,9 @@ Library ------- +- Issue #28257: Improved error message when pass a non-iterable as + a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL. + - Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2509,9 +2509,10 @@ DISPATCH(); } + TARGET(BUILD_TUPLE_UNPACK_WITH_CALL) TARGET(BUILD_TUPLE_UNPACK) TARGET(BUILD_LIST_UNPACK) { - int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK; + int convert_to_tuple = opcode != BUILD_LIST_UNPACK; Py_ssize_t i; PyObject *sum = PyList_New(0); PyObject *return_value; @@ -2524,6 +2525,16 @@ none_val = _PyList_Extend((PyListObject *)sum, PEEK(i)); if (none_val == NULL) { + if (opcode == BUILD_TUPLE_UNPACK_WITH_CALL && + PyErr_ExceptionMatches(PyExc_TypeError)) { + PyObject *func = PEEK(1 + oparg); + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after * " + "must be an iterable, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + PEEK(i)->ob_type->tp_name); + } Py_DECREF(sum); goto error; } diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -987,9 +987,9 @@ return 1-oparg; case BUILD_LIST_UNPACK: case BUILD_TUPLE_UNPACK: + case BUILD_TUPLE_UNPACK_WITH_CALL: case BUILD_SET_UNPACK: case BUILD_MAP_UNPACK: - return 1 - oparg; case BUILD_MAP_UNPACK_WITH_CALL: return 1 - oparg; case BUILD_MAP: @@ -3549,7 +3549,7 @@ if (nsubargs > 1) { /* If we ended up with more than one stararg, we need to concatenate them into a single sequence. */ - ADDOP_I(c, BUILD_TUPLE_UNPACK, nsubargs); + ADDOP_I(c, BUILD_TUPLE_UNPACK_WITH_CALL, nsubargs); } else if (nsubargs == 0) { ADDOP_I(c, BUILD_TUPLE, 0); diff --git a/Python/importlib_external.h b/Python/importlib_external.h --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -242,7 +242,7 @@ 101,95,97,116,111,109,105,99,106,0,0,0,115,26,0,0, 0,0,5,16,1,6,1,26,1,2,3,14,1,20,1,16, 1,14,1,2,1,14,1,14,1,6,1,114,58,0,0,0, - 105,49,13,0,0,233,2,0,0,0,114,15,0,0,0,115, + 105,50,13,0,0,233,2,0,0,0,114,15,0,0,0,115, 2,0,0,0,13,10,90,11,95,95,112,121,99,97,99,104, 101,95,95,122,4,111,112,116,45,122,3,46,112,121,122,4, 46,112,121,99,78,41,1,218,12,111,112,116,105,109,105,122, @@ -346,7 +346,7 @@ 103,90,15,97,108,109,111,115,116,95,102,105,108,101,110,97, 109,101,114,4,0,0,0,114,4,0,0,0,114,6,0,0, 0,218,17,99,97,99,104,101,95,102,114,111,109,95,115,111, - 117,114,99,101,5,1,0,0,115,48,0,0,0,0,18,8, + 117,114,99,101,6,1,0,0,115,48,0,0,0,0,18,8, 1,6,1,6,1,8,1,4,1,8,1,12,1,10,1,12, 1,16,1,8,1,8,1,8,1,24,1,8,1,12,1,6, 2,8,1,8,1,8,1,8,1,14,1,14,1,114,83,0, @@ -420,7 +420,7 @@ 112,116,95,108,101,118,101,108,90,13,98,97,115,101,95,102, 105,108,101,110,97,109,101,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,17,115,111,117,114,99,101,95,102, - 114,111,109,95,99,97,99,104,101,50,1,0,0,115,46,0, + 114,111,109,95,99,97,99,104,101,51,1,0,0,115,46,0, 0,0,0,9,12,1,8,1,10,1,12,1,12,1,8,1, 6,1,10,1,10,1,8,1,6,1,10,1,8,1,16,1, 10,1,6,1,8,1,16,1,8,1,6,1,8,1,14,1, @@ -456,7 +456,7 @@ 115,105,111,110,218,11,115,111,117,114,99,101,95,112,97,116, 104,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, 218,15,95,103,101,116,95,115,111,117,114,99,101,102,105,108, - 101,84,1,0,0,115,20,0,0,0,0,7,12,1,4,1, + 101,85,1,0,0,115,20,0,0,0,0,7,12,1,4,1, 16,1,26,1,4,1,2,1,12,1,18,1,18,1,114,95, 0,0,0,99,1,0,0,0,0,0,0,0,1,0,0,0, 11,0,0,0,67,0,0,0,115,74,0,0,0,124,0,106, @@ -469,7 +469,7 @@ 0,0,114,83,0,0,0,114,70,0,0,0,114,78,0,0, 0,41,1,218,8,102,105,108,101,110,97,109,101,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,11,95,103, - 101,116,95,99,97,99,104,101,100,103,1,0,0,115,16,0, + 101,116,95,99,97,99,104,101,100,104,1,0,0,115,16,0, 0,0,0,1,14,1,2,1,8,1,14,1,8,1,14,1, 6,2,114,99,0,0,0,99,1,0,0,0,0,0,0,0, 2,0,0,0,11,0,0,0,67,0,0,0,115,52,0,0, @@ -483,7 +483,7 @@ 0,233,128,0,0,0,41,3,114,41,0,0,0,114,43,0, 0,0,114,42,0,0,0,41,2,114,37,0,0,0,114,44, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,10,95,99,97,108,99,95,109,111,100,101,115,1, + 0,0,218,10,95,99,97,108,99,95,109,111,100,101,116,1, 0,0,115,12,0,0,0,0,2,2,1,14,1,14,1,10, 3,8,1,114,101,0,0,0,99,1,0,0,0,0,0,0, 0,3,0,0,0,11,0,0,0,3,0,0,0,115,68,0, @@ -512,7 +512,7 @@ 0,124,1,100,0,107,8,114,16,124,0,106,0,125,1,110, 32,124,0,106,0,124,1,107,3,114,48,116,1,100,1,124, 0,106,0,124,1,102,2,22,0,124,1,100,2,141,2,130, - 1,136,0,124,0,124,1,102,2,124,2,152,2,124,3,142, + 1,136,0,124,0,124,1,102,2,124,2,158,2,124,3,142, 1,83,0,41,3,78,122,30,108,111,97,100,101,114,32,102, 111,114,32,37,115,32,99,97,110,110,111,116,32,104,97,110, 100,108,101,32,37,115,41,1,218,4,110,97,109,101,41,2, @@ -521,7 +521,7 @@ 4,97,114,103,115,90,6,107,119,97,114,103,115,41,1,218, 6,109,101,116,104,111,100,114,4,0,0,0,114,6,0,0, 0,218,19,95,99,104,101,99,107,95,110,97,109,101,95,119, - 114,97,112,112,101,114,135,1,0,0,115,12,0,0,0,0, + 114,97,112,112,101,114,136,1,0,0,115,12,0,0,0,0, 1,8,1,8,1,10,1,4,1,18,1,122,40,95,99,104, 101,99,107,95,110,97,109,101,46,60,108,111,99,97,108,115, 62,46,95,99,104,101,99,107,95,110,97,109,101,95,119,114, @@ -540,7 +540,7 @@ 95,95,100,105,99,116,95,95,218,6,117,112,100,97,116,101, 41,3,90,3,110,101,119,90,3,111,108,100,114,55,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,5,95,119,114,97,112,146,1,0,0,115,8,0,0,0, + 218,5,95,119,114,97,112,147,1,0,0,115,8,0,0,0, 0,1,10,1,10,1,22,1,122,26,95,99,104,101,99,107, 95,110,97,109,101,46,60,108,111,99,97,108,115,62,46,95, 119,114,97,112,41,1,78,41,3,218,10,95,98,111,111,116, @@ -548,7 +548,7 @@ 69,114,114,111,114,41,3,114,106,0,0,0,114,107,0,0, 0,114,117,0,0,0,114,4,0,0,0,41,1,114,106,0, 0,0,114,6,0,0,0,218,11,95,99,104,101,99,107,95, - 110,97,109,101,127,1,0,0,115,14,0,0,0,0,8,14, + 110,97,109,101,128,1,0,0,115,14,0,0,0,0,8,14, 7,2,1,10,1,14,2,14,5,10,1,114,120,0,0,0, 99,2,0,0,0,0,0,0,0,5,0,0,0,4,0,0, 0,67,0,0,0,115,60,0,0,0,124,0,106,0,124,1, @@ -576,7 +576,7 @@ 97,100,101,114,218,8,112,111,114,116,105,111,110,115,218,3, 109,115,103,114,4,0,0,0,114,4,0,0,0,114,6,0, 0,0,218,17,95,102,105,110,100,95,109,111,100,117,108,101, - 95,115,104,105,109,155,1,0,0,115,10,0,0,0,0,10, + 95,115,104,105,109,156,1,0,0,115,10,0,0,0,0,10, 14,1,16,1,4,1,22,1,114,127,0,0,0,99,4,0, 0,0,0,0,0,0,11,0,0,0,22,0,0,0,67,0, 0,0,115,136,1,0,0,105,0,125,4,124,2,100,1,107, @@ -656,7 +656,7 @@ 218,11,115,111,117,114,99,101,95,115,105,122,101,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,25,95,118, 97,108,105,100,97,116,101,95,98,121,116,101,99,111,100,101, - 95,104,101,97,100,101,114,172,1,0,0,115,76,0,0,0, + 95,104,101,97,100,101,114,173,1,0,0,115,76,0,0,0, 0,11,4,1,8,1,10,3,4,1,8,1,8,1,12,1, 12,1,12,1,8,1,12,1,12,1,14,1,12,1,10,1, 12,1,10,1,12,1,10,1,12,1,8,1,10,1,2,1, @@ -685,7 +685,7 @@ 41,5,114,56,0,0,0,114,102,0,0,0,114,93,0,0, 0,114,94,0,0,0,218,4,99,111,100,101,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,218,17,95,99,111, - 109,112,105,108,101,95,98,121,116,101,99,111,100,101,227,1, + 109,112,105,108,101,95,98,121,116,101,99,111,100,101,228,1, 0,0,115,16,0,0,0,0,2,10,1,10,1,12,1,8, 1,12,1,6,2,10,1,114,145,0,0,0,114,62,0,0, 0,99,3,0,0,0,0,0,0,0,4,0,0,0,3,0, @@ -704,7 +704,7 @@ 112,115,41,4,114,144,0,0,0,114,130,0,0,0,114,138, 0,0,0,114,56,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,6,0,0,0,218,17,95,99,111,100,101,95,116, - 111,95,98,121,116,101,99,111,100,101,239,1,0,0,115,10, + 111,95,98,121,116,101,99,111,100,101,240,1,0,0,115,10, 0,0,0,0,3,8,1,14,1,14,1,16,1,114,148,0, 0,0,99,1,0,0,0,0,0,0,0,5,0,0,0,4, 0,0,0,67,0,0,0,115,62,0,0,0,100,1,100,2, @@ -731,7 +731,7 @@ 110,101,218,8,101,110,99,111,100,105,110,103,90,15,110,101, 119,108,105,110,101,95,100,101,99,111,100,101,114,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,13,100,101, - 99,111,100,101,95,115,111,117,114,99,101,249,1,0,0,115, + 99,111,100,101,95,115,111,117,114,99,101,250,1,0,0,115, 10,0,0,0,0,5,8,1,12,1,10,1,12,1,114,153, 0,0,0,41,2,114,124,0,0,0,218,26,115,117,98,109, 111,100,117,108,101,95,115,101,97,114,99,104,95,108,111,99, @@ -793,7 +793,7 @@ 0,0,0,90,7,100,105,114,110,97,109,101,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,218,23,115,112,101, 99,95,102,114,111,109,95,102,105,108,101,95,108,111,99,97, - 116,105,111,110,10,2,0,0,115,62,0,0,0,0,12,8, + 116,105,111,110,11,2,0,0,115,62,0,0,0,0,12,8, 4,4,1,10,2,2,1,14,1,14,1,8,2,10,8,16, 1,6,3,8,1,16,1,14,1,10,1,6,1,6,2,4, 3,8,2,10,1,2,1,14,1,14,1,6,2,4,1,8, @@ -829,7 +829,7 @@ 18,72,75,69,89,95,76,79,67,65,76,95,77,65,67,72, 73,78,69,41,2,218,3,99,108,115,114,5,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,14, - 95,111,112,101,110,95,114,101,103,105,115,116,114,121,90,2, + 95,111,112,101,110,95,114,101,103,105,115,116,114,121,91,2, 0,0,115,8,0,0,0,0,2,2,1,14,1,14,1,122, 36,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, 70,105,110,100,101,114,46,95,111,112,101,110,95,114,101,103, @@ -855,7 +855,7 @@ 121,95,107,101,121,114,5,0,0,0,90,4,104,107,101,121, 218,8,102,105,108,101,112,97,116,104,114,4,0,0,0,114, 4,0,0,0,114,6,0,0,0,218,16,95,115,101,97,114, - 99,104,95,114,101,103,105,115,116,114,121,97,2,0,0,115, + 99,104,95,114,101,103,105,115,116,114,121,98,2,0,0,115, 22,0,0,0,0,2,6,1,8,2,6,1,6,1,22,1, 2,1,12,1,26,1,14,1,6,1,122,38,87,105,110,100, 111,119,115,82,101,103,105,115,116,114,121,70,105,110,100,101, @@ -877,7 +877,7 @@ 0,0,114,37,0,0,0,218,6,116,97,114,103,101,116,114, 174,0,0,0,114,124,0,0,0,114,164,0,0,0,114,162, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,9,102,105,110,100,95,115,112,101,99,112,2,0, + 0,0,218,9,102,105,110,100,95,115,112,101,99,113,2,0, 0,115,26,0,0,0,0,2,10,1,8,1,4,1,2,1, 12,1,14,1,6,1,16,1,14,1,6,1,8,1,8,1, 122,31,87,105,110,100,111,119,115,82,101,103,105,115,116,114, @@ -896,7 +896,7 @@ 41,2,114,178,0,0,0,114,124,0,0,0,41,4,114,168, 0,0,0,114,123,0,0,0,114,37,0,0,0,114,162,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,218,11,102,105,110,100,95,109,111,100,117,108,101,128,2, + 0,218,11,102,105,110,100,95,109,111,100,117,108,101,129,2, 0,0,115,8,0,0,0,0,7,12,1,8,1,8,2,122, 33,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, 70,105,110,100,101,114,46,102,105,110,100,95,109,111,100,117, @@ -906,7 +906,7 @@ 99,108,97,115,115,109,101,116,104,111,100,114,169,0,0,0, 114,175,0,0,0,114,178,0,0,0,114,179,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,166,0,0,0,78,2,0,0,115,20,0,0, + 0,0,0,114,166,0,0,0,79,2,0,0,115,20,0,0, 0,8,2,4,3,4,3,4,2,4,2,12,7,12,15,2, 1,12,15,2,1,114,166,0,0,0,99,0,0,0,0,0, 0,0,0,0,0,0,0,2,0,0,0,64,0,0,0,115, @@ -941,7 +941,7 @@ 114,123,0,0,0,114,98,0,0,0,90,13,102,105,108,101, 110,97,109,101,95,98,97,115,101,90,9,116,97,105,108,95, 110,97,109,101,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,157,0,0,0,147,2,0,0,115,8,0,0, + 0,0,0,114,157,0,0,0,148,2,0,0,115,8,0,0, 0,0,3,18,1,16,1,14,1,122,24,95,76,111,97,100, 101,114,66,97,115,105,99,115,46,105,115,95,112,97,99,107, 97,103,101,99,2,0,0,0,0,0,0,0,2,0,0,0, @@ -951,7 +951,7 @@ 111,100,117,108,101,32,99,114,101,97,116,105,111,110,46,78, 114,4,0,0,0,41,2,114,104,0,0,0,114,162,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,13,99,114,101,97,116,101,95,109,111,100,117,108,101,155, + 218,13,99,114,101,97,116,101,95,109,111,100,117,108,101,156, 2,0,0,115,0,0,0,0,122,27,95,76,111,97,100,101, 114,66,97,115,105,99,115,46,99,114,101,97,116,101,95,109, 111,100,117,108,101,99,2,0,0,0,0,0,0,0,3,0, @@ -971,7 +971,7 @@ 218,4,101,120,101,99,114,115,0,0,0,41,3,114,104,0, 0,0,218,6,109,111,100,117,108,101,114,144,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,11, - 101,120,101,99,95,109,111,100,117,108,101,158,2,0,0,115, + 101,120,101,99,95,109,111,100,117,108,101,159,2,0,0,115, 10,0,0,0,0,2,12,1,8,1,6,1,10,1,122,25, 95,76,111,97,100,101,114,66,97,115,105,99,115,46,101,120, 101,99,95,109,111,100,117,108,101,99,2,0,0,0,0,0, @@ -982,14 +982,14 @@ 118,0,0,0,218,17,95,108,111,97,100,95,109,111,100,117, 108,101,95,115,104,105,109,41,2,114,104,0,0,0,114,123, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,11,108,111,97,100,95,109,111,100,117,108,101,166, + 0,0,218,11,108,111,97,100,95,109,111,100,117,108,101,167, 2,0,0,115,2,0,0,0,0,2,122,25,95,76,111,97, 100,101,114,66,97,115,105,99,115,46,108,111,97,100,95,109, 111,100,117,108,101,78,41,8,114,109,0,0,0,114,108,0, 0,0,114,110,0,0,0,114,111,0,0,0,114,157,0,0, 0,114,183,0,0,0,114,188,0,0,0,114,190,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,181,0,0,0,142,2,0,0,115,10,0, + 6,0,0,0,114,181,0,0,0,143,2,0,0,115,10,0, 0,0,8,3,4,2,8,8,8,3,8,8,114,181,0,0, 0,99,0,0,0,0,0,0,0,0,0,0,0,0,3,0, 0,0,64,0,0,0,115,74,0,0,0,101,0,90,1,100, @@ -1015,7 +1015,7 @@ 218,7,73,79,69,114,114,111,114,41,2,114,104,0,0,0, 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, 6,0,0,0,218,10,112,97,116,104,95,109,116,105,109,101, - 173,2,0,0,115,2,0,0,0,0,6,122,23,83,111,117, + 174,2,0,0,115,2,0,0,0,0,6,122,23,83,111,117, 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,109, 116,105,109,101,99,2,0,0,0,0,0,0,0,2,0,0, 0,3,0,0,0,67,0,0,0,115,14,0,0,0,100,1, @@ -1050,7 +1050,7 @@ 0,0,41,1,114,193,0,0,0,41,2,114,104,0,0,0, 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, 6,0,0,0,218,10,112,97,116,104,95,115,116,97,116,115, - 181,2,0,0,115,2,0,0,0,0,11,122,23,83,111,117, + 182,2,0,0,115,2,0,0,0,0,11,122,23,83,111,117, 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,115, 116,97,116,115,99,4,0,0,0,0,0,0,0,4,0,0, 0,3,0,0,0,67,0,0,0,115,12,0,0,0,124,0, @@ -1073,7 +1073,7 @@ 114,104,0,0,0,114,94,0,0,0,90,10,99,97,99,104, 101,95,112,97,116,104,114,56,0,0,0,114,4,0,0,0, 114,4,0,0,0,114,6,0,0,0,218,15,95,99,97,99, - 104,101,95,98,121,116,101,99,111,100,101,194,2,0,0,115, + 104,101,95,98,121,116,101,99,111,100,101,195,2,0,0,115, 2,0,0,0,0,8,122,28,83,111,117,114,99,101,76,111, 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, 99,111,100,101,99,3,0,0,0,0,0,0,0,3,0,0, @@ -1090,7 +1090,7 @@ 101,115,46,10,32,32,32,32,32,32,32,32,78,114,4,0, 0,0,41,3,114,104,0,0,0,114,37,0,0,0,114,56, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,195,0,0,0,204,2,0,0,115,0,0,0,0, + 0,0,114,195,0,0,0,205,2,0,0,115,0,0,0,0, 122,21,83,111,117,114,99,101,76,111,97,100,101,114,46,115, 101,116,95,100,97,116,97,99,2,0,0,0,0,0,0,0, 5,0,0,0,16,0,0,0,67,0,0,0,115,82,0,0, @@ -1111,7 +1111,7 @@ 0,0,0,114,123,0,0,0,114,37,0,0,0,114,151,0, 0,0,218,3,101,120,99,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,10,103,101,116,95,115,111,117,114, - 99,101,211,2,0,0,115,14,0,0,0,0,2,10,1,2, + 99,101,212,2,0,0,115,14,0,0,0,0,2,10,1,2, 1,14,1,16,1,4,1,28,1,122,23,83,111,117,114,99, 101,76,111,97,100,101,114,46,103,101,116,95,115,111,117,114, 99,101,114,31,0,0,0,41,1,218,9,95,111,112,116,105, @@ -1132,7 +1132,7 @@ 0,218,7,99,111,109,112,105,108,101,41,4,114,104,0,0, 0,114,56,0,0,0,114,37,0,0,0,114,200,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, - 14,115,111,117,114,99,101,95,116,111,95,99,111,100,101,221, + 14,115,111,117,114,99,101,95,116,111,95,99,111,100,101,222, 2,0,0,115,4,0,0,0,0,5,12,1,122,27,83,111, 117,114,99,101,76,111,97,100,101,114,46,115,111,117,114,99, 101,95,116,111,95,99,111,100,101,99,2,0,0,0,0,0, @@ -1189,7 +1189,7 @@ 114,56,0,0,0,218,10,98,121,116,101,115,95,100,97,116, 97,114,151,0,0,0,90,11,99,111,100,101,95,111,98,106, 101,99,116,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,184,0,0,0,229,2,0,0,115,78,0,0,0, + 0,0,114,184,0,0,0,230,2,0,0,115,78,0,0,0, 0,7,10,1,4,1,2,1,12,1,14,1,10,2,2,1, 14,1,14,1,6,2,12,1,2,1,14,1,14,1,6,2, 2,1,4,1,4,1,12,1,18,1,6,2,8,1,6,1, @@ -1201,7 +1201,7 @@ 0,114,194,0,0,0,114,196,0,0,0,114,195,0,0,0, 114,199,0,0,0,114,203,0,0,0,114,184,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,191,0,0,0,171,2,0,0,115,14,0,0, + 0,0,0,114,191,0,0,0,172,2,0,0,115,14,0,0, 0,8,2,8,8,8,13,8,10,8,7,8,10,14,8,114, 191,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, 0,4,0,0,0,0,0,0,0,115,80,0,0,0,101,0, @@ -1228,7 +1228,7 @@ 2,114,102,0,0,0,114,37,0,0,0,41,3,114,104,0, 0,0,114,123,0,0,0,114,37,0,0,0,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,114,182,0,0,0, - 30,3,0,0,115,4,0,0,0,0,3,6,1,122,19,70, + 31,3,0,0,115,4,0,0,0,0,3,6,1,122,19,70, 105,108,101,76,111,97,100,101,114,46,95,95,105,110,105,116, 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, 0,0,0,67,0,0,0,115,24,0,0,0,124,0,106,0, @@ -1236,7 +1236,7 @@ 107,2,83,0,41,1,78,41,2,218,9,95,95,99,108,97, 115,115,95,95,114,115,0,0,0,41,2,114,104,0,0,0, 218,5,111,116,104,101,114,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,6,95,95,101,113,95,95,36,3, + 0,114,6,0,0,0,218,6,95,95,101,113,95,95,37,3, 0,0,115,4,0,0,0,0,1,12,1,122,17,70,105,108, 101,76,111,97,100,101,114,46,95,95,101,113,95,95,99,1, 0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,67, @@ -1245,7 +1245,7 @@ 3,218,4,104,97,115,104,114,102,0,0,0,114,37,0,0, 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,6,0,0,0,218,8,95,95,104,97,115,104,95, - 95,40,3,0,0,115,2,0,0,0,0,1,122,19,70,105, + 95,41,3,0,0,115,2,0,0,0,0,1,122,19,70,105, 108,101,76,111,97,100,101,114,46,95,95,104,97,115,104,95, 95,99,2,0,0,0,0,0,0,0,2,0,0,0,3,0, 0,0,3,0,0,0,115,16,0,0,0,116,0,116,1,124, @@ -1259,7 +1259,7 @@ 32,32,32,41,3,218,5,115,117,112,101,114,114,207,0,0, 0,114,190,0,0,0,41,2,114,104,0,0,0,114,123,0, 0,0,41,1,114,208,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,190,0,0,0,43,3,0,0,115,2,0,0, + 0,0,0,114,190,0,0,0,44,3,0,0,115,2,0,0, 0,0,10,122,22,70,105,108,101,76,111,97,100,101,114,46, 108,111,97,100,95,109,111,100,117,108,101,99,2,0,0,0, 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, @@ -1270,7 +1270,7 @@ 101,32,102,105,110,100,101,114,46,41,1,114,37,0,0,0, 41,2,114,104,0,0,0,114,123,0,0,0,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,114,155,0,0,0, - 55,3,0,0,115,2,0,0,0,0,3,122,23,70,105,108, + 56,3,0,0,115,2,0,0,0,0,3,122,23,70,105,108, 101,76,111,97,100,101,114,46,103,101,116,95,102,105,108,101, 110,97,109,101,99,2,0,0,0,0,0,0,0,3,0,0, 0,9,0,0,0,67,0,0,0,115,32,0,0,0,116,0, @@ -1282,7 +1282,7 @@ 52,0,0,0,114,53,0,0,0,90,4,114,101,97,100,41, 3,114,104,0,0,0,114,37,0,0,0,114,57,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 197,0,0,0,60,3,0,0,115,4,0,0,0,0,2,14, + 197,0,0,0,61,3,0,0,115,4,0,0,0,0,2,14, 1,122,19,70,105,108,101,76,111,97,100,101,114,46,103,101, 116,95,100,97,116,97,78,41,12,114,109,0,0,0,114,108, 0,0,0,114,110,0,0,0,114,111,0,0,0,114,182,0, @@ -1290,7 +1290,7 @@ 0,114,190,0,0,0,114,155,0,0,0,114,197,0,0,0, 90,13,95,95,99,108,97,115,115,99,101,108,108,95,95,114, 4,0,0,0,114,4,0,0,0,41,1,114,208,0,0,0, - 114,6,0,0,0,114,207,0,0,0,25,3,0,0,115,14, + 114,6,0,0,0,114,207,0,0,0,26,3,0,0,115,14, 0,0,0,8,3,4,2,8,6,8,4,8,3,16,12,12, 5,114,207,0,0,0,99,0,0,0,0,0,0,0,0,0, 0,0,0,3,0,0,0,64,0,0,0,115,46,0,0,0, @@ -1312,7 +1312,7 @@ 116,105,109,101,90,7,115,116,95,115,105,122,101,41,3,114, 104,0,0,0,114,37,0,0,0,114,205,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,194,0, - 0,0,70,3,0,0,115,4,0,0,0,0,2,8,1,122, + 0,0,71,3,0,0,115,4,0,0,0,0,2,8,1,122, 27,83,111,117,114,99,101,70,105,108,101,76,111,97,100,101, 114,46,112,97,116,104,95,115,116,97,116,115,99,4,0,0, 0,0,0,0,0,5,0,0,0,5,0,0,0,67,0,0, @@ -1322,7 +1322,7 @@ 0,114,195,0,0,0,41,5,114,104,0,0,0,114,94,0, 0,0,114,93,0,0,0,114,56,0,0,0,114,44,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,196,0,0,0,75,3,0,0,115,4,0,0,0,0,2, + 114,196,0,0,0,76,3,0,0,115,4,0,0,0,0,2, 8,1,122,32,83,111,117,114,99,101,70,105,108,101,76,111, 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, 99,111,100,101,105,182,1,0,0,41,1,114,217,0,0,0, @@ -1357,7 +1357,7 @@ 0,218,6,112,97,114,101,110,116,114,98,0,0,0,114,29, 0,0,0,114,25,0,0,0,114,198,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,114,195,0,0, - 0,80,3,0,0,115,42,0,0,0,0,2,12,1,4,2, + 0,81,3,0,0,115,42,0,0,0,0,2,12,1,4,2, 16,1,12,1,14,2,14,1,10,1,2,1,14,1,14,2, 6,1,16,3,6,1,8,1,20,1,2,1,12,1,16,1, 16,2,8,1,122,25,83,111,117,114,99,101,70,105,108,101, @@ -1365,7 +1365,7 @@ 41,7,114,109,0,0,0,114,108,0,0,0,114,110,0,0, 0,114,111,0,0,0,114,194,0,0,0,114,196,0,0,0, 114,195,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,215,0,0,0,66,3, + 4,0,0,0,114,6,0,0,0,114,215,0,0,0,67,3, 0,0,115,8,0,0,0,8,2,4,2,8,5,8,5,114, 215,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, 0,2,0,0,0,64,0,0,0,115,32,0,0,0,101,0, @@ -1385,7 +1385,7 @@ 0,114,197,0,0,0,114,139,0,0,0,114,145,0,0,0, 41,5,114,104,0,0,0,114,123,0,0,0,114,37,0,0, 0,114,56,0,0,0,114,206,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,115, + 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,116, 3,0,0,115,8,0,0,0,0,1,10,1,10,1,14,1, 122,29,83,111,117,114,99,101,108,101,115,115,70,105,108,101, 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, @@ -1395,14 +1395,14 @@ 116,104,101,114,101,32,105,115,32,110,111,32,115,111,117,114, 99,101,32,99,111,100,101,46,78,114,4,0,0,0,41,2, 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,199,0,0,0,121,3, + 4,0,0,0,114,6,0,0,0,114,199,0,0,0,122,3, 0,0,115,2,0,0,0,0,2,122,31,83,111,117,114,99, 101,108,101,115,115,70,105,108,101,76,111,97,100,101,114,46, 103,101,116,95,115,111,117,114,99,101,78,41,6,114,109,0, 0,0,114,108,0,0,0,114,110,0,0,0,114,111,0,0, 0,114,184,0,0,0,114,199,0,0,0,114,4,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 220,0,0,0,111,3,0,0,115,6,0,0,0,8,2,4, + 220,0,0,0,112,3,0,0,115,6,0,0,0,8,2,4, 2,8,6,114,220,0,0,0,99,0,0,0,0,0,0,0, 0,0,0,0,0,3,0,0,0,64,0,0,0,115,92,0, 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, @@ -1424,7 +1424,7 @@ 78,41,2,114,102,0,0,0,114,37,0,0,0,41,3,114, 104,0,0,0,114,102,0,0,0,114,37,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,182,0, - 0,0,138,3,0,0,115,4,0,0,0,0,1,6,1,122, + 0,0,139,3,0,0,115,4,0,0,0,0,1,6,1,122, 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, 97,100,101,114,46,95,95,105,110,105,116,95,95,99,2,0, 0,0,0,0,0,0,2,0,0,0,2,0,0,0,67,0, @@ -1432,7 +1432,7 @@ 2,111,22,124,0,106,1,124,1,106,1,107,2,83,0,41, 1,78,41,2,114,208,0,0,0,114,115,0,0,0,41,2, 114,104,0,0,0,114,209,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,210,0,0,0,142,3, + 4,0,0,0,114,6,0,0,0,114,210,0,0,0,143,3, 0,0,115,4,0,0,0,0,1,12,1,122,26,69,120,116, 101,110,115,105,111,110,70,105,108,101,76,111,97,100,101,114, 46,95,95,101,113,95,95,99,1,0,0,0,0,0,0,0, @@ -1441,7 +1441,7 @@ 1,65,0,83,0,41,1,78,41,3,114,211,0,0,0,114, 102,0,0,0,114,37,0,0,0,41,1,114,104,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 212,0,0,0,146,3,0,0,115,2,0,0,0,0,1,122, + 212,0,0,0,147,3,0,0,115,2,0,0,0,0,1,122, 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, 97,100,101,114,46,95,95,104,97,115,104,95,95,99,2,0, 0,0,0,0,0,0,3,0,0,0,4,0,0,0,67,0, @@ -1458,7 +1458,7 @@ 0,0,0,114,102,0,0,0,114,37,0,0,0,41,3,114, 104,0,0,0,114,162,0,0,0,114,187,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,183,0, - 0,0,149,3,0,0,115,10,0,0,0,0,2,4,1,10, + 0,0,150,3,0,0,115,10,0,0,0,0,2,4,1,10, 1,6,1,12,1,122,33,69,120,116,101,110,115,105,111,110, 70,105,108,101,76,111,97,100,101,114,46,99,114,101,97,116, 101,95,109,111,100,117,108,101,99,2,0,0,0,0,0,0, @@ -1475,7 +1475,7 @@ 105,99,114,133,0,0,0,114,102,0,0,0,114,37,0,0, 0,41,2,114,104,0,0,0,114,187,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,114,188,0,0, - 0,157,3,0,0,115,6,0,0,0,0,2,14,1,6,1, + 0,158,3,0,0,115,6,0,0,0,0,2,14,1,6,1, 122,31,69,120,116,101,110,115,105,111,110,70,105,108,101,76, 111,97,100,101,114,46,101,120,101,99,95,109,111,100,117,108, 101,99,2,0,0,0,0,0,0,0,2,0,0,0,4,0, @@ -1492,7 +1492,7 @@ 182,0,0,0,78,114,4,0,0,0,41,2,114,24,0,0, 0,218,6,115,117,102,102,105,120,41,1,218,9,102,105,108, 101,95,110,97,109,101,114,4,0,0,0,114,6,0,0,0, - 250,9,60,103,101,110,101,120,112,114,62,166,3,0,0,115, + 250,9,60,103,101,110,101,120,112,114,62,167,3,0,0,115, 2,0,0,0,4,1,122,49,69,120,116,101,110,115,105,111, 110,70,105,108,101,76,111,97,100,101,114,46,105,115,95,112, 97,99,107,97,103,101,46,60,108,111,99,97,108,115,62,46, @@ -1501,7 +1501,7 @@ 78,83,73,79,78,95,83,85,70,70,73,88,69,83,41,2, 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,41, 1,114,223,0,0,0,114,6,0,0,0,114,157,0,0,0, - 163,3,0,0,115,6,0,0,0,0,2,14,1,12,1,122, + 164,3,0,0,115,6,0,0,0,0,2,14,1,12,1,122, 30,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, 97,100,101,114,46,105,115,95,112,97,99,107,97,103,101,99, 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, @@ -1512,7 +1512,7 @@ 101,32,97,32,99,111,100,101,32,111,98,106,101,99,116,46, 78,114,4,0,0,0,41,2,114,104,0,0,0,114,123,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,184,0,0,0,169,3,0,0,115,2,0,0,0,0, + 0,114,184,0,0,0,170,3,0,0,115,2,0,0,0,0, 2,122,28,69,120,116,101,110,115,105,111,110,70,105,108,101, 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, @@ -1522,7 +1522,7 @@ 115,32,104,97,118,101,32,110,111,32,115,111,117,114,99,101, 32,99,111,100,101,46,78,114,4,0,0,0,41,2,114,104, 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,199,0,0,0,173,3,0,0, + 0,0,114,6,0,0,0,114,199,0,0,0,174,3,0,0, 115,2,0,0,0,0,2,122,30,69,120,116,101,110,115,105, 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, 95,115,111,117,114,99,101,99,2,0,0,0,0,0,0,0, @@ -1533,7 +1533,7 @@ 32,102,111,117,110,100,32,98,121,32,116,104,101,32,102,105, 110,100,101,114,46,41,1,114,37,0,0,0,41,2,114,104, 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,155,0,0,0,177,3,0,0, + 0,0,114,6,0,0,0,114,155,0,0,0,178,3,0,0, 115,2,0,0,0,0,3,122,32,69,120,116,101,110,115,105, 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, 95,102,105,108,101,110,97,109,101,78,41,14,114,109,0,0, @@ -1542,7 +1542,7 @@ 183,0,0,0,114,188,0,0,0,114,157,0,0,0,114,184, 0,0,0,114,199,0,0,0,114,120,0,0,0,114,155,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,114,221,0,0,0,130,3,0,0,115, + 0,114,6,0,0,0,114,221,0,0,0,131,3,0,0,115, 20,0,0,0,8,6,4,2,8,4,8,4,8,3,8,8, 8,6,8,6,8,4,8,4,114,221,0,0,0,99,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,64,0, @@ -1583,7 +1583,7 @@ 12,95,112,97,116,104,95,102,105,110,100,101,114,41,4,114, 104,0,0,0,114,102,0,0,0,114,37,0,0,0,218,11, 112,97,116,104,95,102,105,110,100,101,114,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,182,0,0,0,190, + 114,4,0,0,0,114,6,0,0,0,114,182,0,0,0,191, 3,0,0,115,8,0,0,0,0,1,6,1,6,1,14,1, 122,23,95,78,97,109,101,115,112,97,99,101,80,97,116,104, 46,95,95,105,110,105,116,95,95,99,1,0,0,0,0,0, @@ -1601,7 +1601,7 @@ 0,41,4,114,104,0,0,0,114,219,0,0,0,218,3,100, 111,116,90,2,109,101,114,4,0,0,0,114,4,0,0,0, 114,6,0,0,0,218,23,95,102,105,110,100,95,112,97,114, - 101,110,116,95,112,97,116,104,95,110,97,109,101,115,196,3, + 101,110,116,95,112,97,116,104,95,110,97,109,101,115,197,3, 0,0,115,8,0,0,0,0,2,18,1,8,2,4,3,122, 38,95,78,97,109,101,115,112,97,99,101,80,97,116,104,46, 95,102,105,110,100,95,112,97,114,101,110,116,95,112,97,116, @@ -1614,7 +1614,7 @@ 0,90,18,112,97,114,101,110,116,95,109,111,100,117,108,101, 95,110,97,109,101,90,14,112,97,116,104,95,97,116,116,114, 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,230,0,0,0,206,3,0,0,115,4,0, + 6,0,0,0,114,230,0,0,0,207,3,0,0,115,4,0, 0,0,0,1,12,1,122,31,95,78,97,109,101,115,112,97, 99,101,80,97,116,104,46,95,103,101,116,95,112,97,114,101, 110,116,95,112,97,116,104,99,1,0,0,0,0,0,0,0, @@ -1630,7 +1630,7 @@ 114,104,0,0,0,90,11,112,97,114,101,110,116,95,112,97, 116,104,114,162,0,0,0,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,12,95,114,101,99,97,108,99,117, - 108,97,116,101,210,3,0,0,115,16,0,0,0,0,2,12, + 108,97,116,101,211,3,0,0,115,16,0,0,0,0,2,12, 1,10,1,14,3,18,1,6,1,8,1,6,1,122,27,95, 78,97,109,101,115,112,97,99,101,80,97,116,104,46,95,114, 101,99,97,108,99,117,108,97,116,101,99,1,0,0,0,0, @@ -1639,7 +1639,7 @@ 41,1,78,41,2,218,4,105,116,101,114,114,237,0,0,0, 41,1,114,104,0,0,0,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,8,95,95,105,116,101,114,95,95, - 223,3,0,0,115,2,0,0,0,0,1,122,23,95,78,97, + 224,3,0,0,115,2,0,0,0,0,1,122,23,95,78,97, 109,101,115,112,97,99,101,80,97,116,104,46,95,95,105,116, 101,114,95,95,99,3,0,0,0,0,0,0,0,3,0,0, 0,3,0,0,0,67,0,0,0,115,14,0,0,0,124,2, @@ -1647,7 +1647,7 @@ 1,114,229,0,0,0,41,3,114,104,0,0,0,218,5,105, 110,100,101,120,114,37,0,0,0,114,4,0,0,0,114,4, 0,0,0,114,6,0,0,0,218,11,95,95,115,101,116,105, - 116,101,109,95,95,226,3,0,0,115,2,0,0,0,0,1, + 116,101,109,95,95,227,3,0,0,115,2,0,0,0,0,1, 122,26,95,78,97,109,101,115,112,97,99,101,80,97,116,104, 46,95,95,115,101,116,105,116,101,109,95,95,99,1,0,0, 0,0,0,0,0,1,0,0,0,2,0,0,0,67,0,0, @@ -1655,7 +1655,7 @@ 83,0,41,1,78,41,2,114,33,0,0,0,114,237,0,0, 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,6,0,0,0,218,7,95,95,108,101,110,95,95, - 229,3,0,0,115,2,0,0,0,0,1,122,22,95,78,97, + 230,3,0,0,115,2,0,0,0,0,1,122,22,95,78,97, 109,101,115,112,97,99,101,80,97,116,104,46,95,95,108,101, 110,95,95,99,1,0,0,0,0,0,0,0,1,0,0,0, 2,0,0,0,67,0,0,0,115,12,0,0,0,100,1,106, @@ -1663,7 +1663,7 @@ 97,109,101,115,112,97,99,101,80,97,116,104,40,123,33,114, 125,41,41,2,114,50,0,0,0,114,229,0,0,0,41,1, 114,104,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,8,95,95,114,101,112,114,95,95,232,3, + 6,0,0,0,218,8,95,95,114,101,112,114,95,95,233,3, 0,0,115,2,0,0,0,0,1,122,23,95,78,97,109,101, 115,112,97,99,101,80,97,116,104,46,95,95,114,101,112,114, 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, @@ -1671,7 +1671,7 @@ 106,0,131,0,107,6,83,0,41,1,78,41,1,114,237,0, 0,0,41,2,114,104,0,0,0,218,4,105,116,101,109,114, 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,12, - 95,95,99,111,110,116,97,105,110,115,95,95,235,3,0,0, + 95,95,99,111,110,116,97,105,110,115,95,95,236,3,0,0, 115,2,0,0,0,0,1,122,27,95,78,97,109,101,115,112, 97,99,101,80,97,116,104,46,95,95,99,111,110,116,97,105, 110,115,95,95,99,2,0,0,0,0,0,0,0,2,0,0, @@ -1679,7 +1679,7 @@ 106,0,106,1,124,1,131,1,1,0,100,0,83,0,41,1, 78,41,2,114,229,0,0,0,114,161,0,0,0,41,2,114, 104,0,0,0,114,244,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,161,0,0,0,238,3,0, + 0,0,0,114,6,0,0,0,114,161,0,0,0,239,3,0, 0,115,2,0,0,0,0,1,122,21,95,78,97,109,101,115, 112,97,99,101,80,97,116,104,46,97,112,112,101,110,100,78, 41,14,114,109,0,0,0,114,108,0,0,0,114,110,0,0, @@ -1688,7 +1688,7 @@ 241,0,0,0,114,242,0,0,0,114,243,0,0,0,114,245, 0,0,0,114,161,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,114,227,0,0, - 0,183,3,0,0,115,22,0,0,0,8,5,4,2,8,6, + 0,184,3,0,0,115,22,0,0,0,8,5,4,2,8,6, 8,10,8,4,8,13,8,3,8,3,8,3,8,3,8,3, 114,227,0,0,0,99,0,0,0,0,0,0,0,0,0,0, 0,0,3,0,0,0,64,0,0,0,115,80,0,0,0,101, @@ -1704,7 +1704,7 @@ 1,78,41,2,114,227,0,0,0,114,229,0,0,0,41,4, 114,104,0,0,0,114,102,0,0,0,114,37,0,0,0,114, 233,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,182,0,0,0,244,3,0,0,115,2,0,0, + 0,0,0,114,182,0,0,0,245,3,0,0,115,2,0,0, 0,0,1,122,25,95,78,97,109,101,115,112,97,99,101,76, 111,97,100,101,114,46,95,95,105,110,105,116,95,95,99,2, 0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,67, @@ -1721,21 +1721,21 @@ 112,97,99,101,41,62,41,2,114,50,0,0,0,114,109,0, 0,0,41,2,114,168,0,0,0,114,187,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,109, - 111,100,117,108,101,95,114,101,112,114,247,3,0,0,115,2, + 111,100,117,108,101,95,114,101,112,114,248,3,0,0,115,2, 0,0,0,0,7,122,28,95,78,97,109,101,115,112,97,99, 101,76,111,97,100,101,114,46,109,111,100,117,108,101,95,114, 101,112,114,99,2,0,0,0,0,0,0,0,2,0,0,0, 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, 0,41,2,78,84,114,4,0,0,0,41,2,114,104,0,0, 0,114,123,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,114,157,0,0,0,0,4,0,0,115,2, + 114,6,0,0,0,114,157,0,0,0,1,4,0,0,115,2, 0,0,0,0,1,122,27,95,78,97,109,101,115,112,97,99, 101,76,111,97,100,101,114,46,105,115,95,112,97,99,107,97, 103,101,99,2,0,0,0,0,0,0,0,2,0,0,0,1, 0,0,0,67,0,0,0,115,4,0,0,0,100,1,83,0, 41,2,78,114,32,0,0,0,114,4,0,0,0,41,2,114, 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,199,0,0,0,3,4,0, + 0,0,0,114,6,0,0,0,114,199,0,0,0,4,4,0, 0,115,2,0,0,0,0,1,122,27,95,78,97,109,101,115, 112,97,99,101,76,111,97,100,101,114,46,103,101,116,95,115, 111,117,114,99,101,99,2,0,0,0,0,0,0,0,2,0, @@ -1745,7 +1745,7 @@ 62,114,186,0,0,0,84,41,1,114,201,0,0,0,41,1, 114,202,0,0,0,41,2,114,104,0,0,0,114,123,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,184,0,0,0,6,4,0,0,115,2,0,0,0,0,1, + 114,184,0,0,0,7,4,0,0,115,2,0,0,0,0,1, 122,25,95,78,97,109,101,115,112,97,99,101,76,111,97,100, 101,114,46,103,101,116,95,99,111,100,101,99,2,0,0,0, 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, @@ -1754,14 +1754,14 @@ 99,115,32,102,111,114,32,109,111,100,117,108,101,32,99,114, 101,97,116,105,111,110,46,78,114,4,0,0,0,41,2,114, 104,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,183,0,0,0,9,4,0, + 0,0,0,114,6,0,0,0,114,183,0,0,0,10,4,0, 0,115,0,0,0,0,122,30,95,78,97,109,101,115,112,97, 99,101,76,111,97,100,101,114,46,99,114,101,97,116,101,95, 109,111,100,117,108,101,99,2,0,0,0,0,0,0,0,2, 0,0,0,1,0,0,0,67,0,0,0,115,4,0,0,0, 100,0,83,0,41,1,78,114,4,0,0,0,41,2,114,104, 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,188,0,0,0,12,4,0,0, + 0,0,114,6,0,0,0,114,188,0,0,0,13,4,0,0, 115,2,0,0,0,0,1,122,28,95,78,97,109,101,115,112, 97,99,101,76,111,97,100,101,114,46,101,120,101,99,95,109, 111,100,117,108,101,99,2,0,0,0,0,0,0,0,2,0, @@ -1779,7 +1779,7 @@ 116,104,32,123,33,114,125,41,4,114,118,0,0,0,114,133, 0,0,0,114,229,0,0,0,114,189,0,0,0,41,2,114, 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,190,0,0,0,15,4,0, + 0,0,0,114,6,0,0,0,114,190,0,0,0,16,4,0, 0,115,6,0,0,0,0,7,6,1,8,1,122,28,95,78, 97,109,101,115,112,97,99,101,76,111,97,100,101,114,46,108, 111,97,100,95,109,111,100,117,108,101,78,41,12,114,109,0, @@ -1788,7 +1788,7 @@ 114,199,0,0,0,114,184,0,0,0,114,183,0,0,0,114, 188,0,0,0,114,190,0,0,0,114,4,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,246,0, - 0,0,243,3,0,0,115,16,0,0,0,8,1,8,3,12, + 0,0,244,3,0,0,115,16,0,0,0,8,1,8,3,12, 9,8,3,8,3,8,3,8,3,8,3,114,246,0,0,0, 99,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,64,0,0,0,115,106,0,0,0,101,0,90,1,100,0, @@ -1821,7 +1821,7 @@ 114,95,99,97,99,104,101,218,6,118,97,108,117,101,115,114, 112,0,0,0,114,249,0,0,0,41,2,114,168,0,0,0, 218,6,102,105,110,100,101,114,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,33,4,0,0, + 0,0,114,6,0,0,0,114,249,0,0,0,34,4,0,0, 115,6,0,0,0,0,4,16,1,10,1,122,28,80,97,116, 104,70,105,110,100,101,114,46,105,110,118,97,108,105,100,97, 116,101,95,99,97,99,104,101,115,99,2,0,0,0,0,0, @@ -1841,7 +1841,7 @@ 0,0,114,122,0,0,0,114,103,0,0,0,41,3,114,168, 0,0,0,114,37,0,0,0,90,4,104,111,111,107,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,95, - 112,97,116,104,95,104,111,111,107,115,41,4,0,0,115,16, + 112,97,116,104,95,104,111,111,107,115,42,4,0,0,115,16, 0,0,0,0,3,18,1,12,1,12,1,2,1,8,1,14, 1,12,2,122,22,80,97,116,104,70,105,110,100,101,114,46, 95,112,97,116,104,95,104,111,111,107,115,99,2,0,0,0, @@ -1873,7 +1873,7 @@ 0,114,37,0,0,0,114,252,0,0,0,114,4,0,0,0, 114,4,0,0,0,114,6,0,0,0,218,20,95,112,97,116, 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 54,4,0,0,115,22,0,0,0,0,8,8,1,2,1,12, + 55,4,0,0,115,22,0,0,0,0,8,8,1,2,1,12, 1,14,3,6,1,2,1,14,1,14,1,10,1,16,1,122, 31,80,97,116,104,70,105,110,100,101,114,46,95,112,97,116, 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, @@ -1890,7 +1890,7 @@ 114,123,0,0,0,114,252,0,0,0,114,124,0,0,0,114, 125,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, 0,0,0,114,6,0,0,0,218,16,95,108,101,103,97,99, - 121,95,103,101,116,95,115,112,101,99,76,4,0,0,115,18, + 121,95,103,101,116,95,115,112,101,99,77,4,0,0,115,18, 0,0,0,0,4,10,1,16,2,10,1,4,1,8,1,12, 1,12,1,6,1,122,27,80,97,116,104,70,105,110,100,101, 114,46,95,108,101,103,97,99,121,95,103,101,116,95,115,112, @@ -1922,7 +1922,7 @@ 90,5,101,110,116,114,121,114,252,0,0,0,114,162,0,0, 0,114,125,0,0,0,114,4,0,0,0,114,4,0,0,0, 114,6,0,0,0,218,9,95,103,101,116,95,115,112,101,99, - 91,4,0,0,115,40,0,0,0,0,5,4,1,10,1,14, + 92,4,0,0,115,40,0,0,0,0,5,4,1,10,1,14, 1,2,1,10,1,8,1,10,1,14,2,12,1,8,1,2, 1,10,1,4,1,6,1,8,1,8,5,14,2,12,1,6, 1,122,20,80,97,116,104,70,105,110,100,101,114,46,95,103, @@ -1949,7 +1949,7 @@ 0,114,156,0,0,0,114,227,0,0,0,41,6,114,168,0, 0,0,114,123,0,0,0,114,37,0,0,0,114,177,0,0, 0,114,162,0,0,0,114,3,1,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,123, + 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,124, 4,0,0,115,26,0,0,0,0,6,8,1,6,1,14,1, 8,1,6,1,10,1,6,1,4,3,6,1,16,1,6,2, 6,2,122,20,80,97,116,104,70,105,110,100,101,114,46,102, @@ -1971,7 +1971,7 @@ 2,114,178,0,0,0,114,124,0,0,0,41,4,114,168,0, 0,0,114,123,0,0,0,114,37,0,0,0,114,162,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,179,0,0,0,147,4,0,0,115,8,0,0,0,0,8, + 114,179,0,0,0,148,4,0,0,115,8,0,0,0,0,8, 12,1,8,1,4,1,122,22,80,97,116,104,70,105,110,100, 101,114,46,102,105,110,100,95,109,111,100,117,108,101,41,1, 78,41,2,78,78,41,1,78,41,12,114,109,0,0,0,114, @@ -1979,7 +1979,7 @@ 0,0,0,114,249,0,0,0,114,254,0,0,0,114,0,1, 0,0,114,1,1,0,0,114,4,1,0,0,114,178,0,0, 0,114,179,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,248,0,0,0,29, + 114,4,0,0,0,114,6,0,0,0,114,248,0,0,0,30, 4,0,0,115,22,0,0,0,8,2,4,2,12,8,12,13, 12,22,12,15,2,1,12,31,2,1,12,23,2,1,114,248, 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0, @@ -2023,7 +2023,7 @@ 14,125,1,124,1,136,0,102,2,86,0,1,0,113,2,100, 0,83,0,41,1,78,114,4,0,0,0,41,2,114,24,0, 0,0,114,222,0,0,0,41,1,114,124,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,224,0,0,0,176,4,0, + 0,0,0,114,6,0,0,0,114,224,0,0,0,177,4,0, 0,115,2,0,0,0,4,0,122,38,70,105,108,101,70,105, 110,100,101,114,46,95,95,105,110,105,116,95,95,46,60,108, 111,99,97,108,115,62,46,60,103,101,110,101,120,112,114,62, @@ -2036,7 +2036,7 @@ 0,114,37,0,0,0,218,14,108,111,97,100,101,114,95,100, 101,116,97,105,108,115,90,7,108,111,97,100,101,114,115,114, 164,0,0,0,114,4,0,0,0,41,1,114,124,0,0,0, - 114,6,0,0,0,114,182,0,0,0,170,4,0,0,115,16, + 114,6,0,0,0,114,182,0,0,0,171,4,0,0,115,16, 0,0,0,0,4,4,1,14,1,28,1,6,2,10,1,6, 1,8,1,122,19,70,105,108,101,70,105,110,100,101,114,46, 95,95,105,110,105,116,95,95,99,1,0,0,0,0,0,0, @@ -2046,7 +2046,7 @@ 105,114,101,99,116,111,114,121,32,109,116,105,109,101,46,114, 31,0,0,0,78,114,91,0,0,0,41,1,114,7,1,0, 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,184,4,0,0, + 0,0,114,6,0,0,0,114,249,0,0,0,185,4,0,0, 115,2,0,0,0,0,2,122,28,70,105,108,101,70,105,110, 100,101,114,46,105,110,118,97,108,105,100,97,116,101,95,99, 97,99,104,101,115,99,2,0,0,0,0,0,0,0,3,0, @@ -2069,7 +2069,7 @@ 32,32,78,41,3,114,178,0,0,0,114,124,0,0,0,114, 154,0,0,0,41,3,114,104,0,0,0,114,123,0,0,0, 114,162,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,121,0,0,0,190,4,0,0,115,8,0, + 6,0,0,0,114,121,0,0,0,191,4,0,0,115,8,0, 0,0,0,7,10,1,8,1,8,1,122,22,70,105,108,101, 70,105,110,100,101,114,46,102,105,110,100,95,108,111,97,100, 101,114,99,6,0,0,0,0,0,0,0,7,0,0,0,6, @@ -2080,7 +2080,7 @@ 0,0,0,114,163,0,0,0,114,123,0,0,0,114,37,0, 0,0,90,4,115,109,115,108,114,177,0,0,0,114,124,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,4,1,0,0,202,4,0,0,115,6,0,0,0,0, + 0,114,4,1,0,0,203,4,0,0,115,6,0,0,0,0, 1,10,1,8,1,122,20,70,105,108,101,70,105,110,100,101, 114,46,95,103,101,116,95,115,112,101,99,78,99,3,0,0, 0,0,0,0,0,14,0,0,0,15,0,0,0,67,0,0, @@ -2134,7 +2134,7 @@ 116,104,114,222,0,0,0,114,163,0,0,0,90,13,105,110, 105,116,95,102,105,108,101,110,97,109,101,90,9,102,117,108, 108,95,112,97,116,104,114,162,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,207, + 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,208, 4,0,0,115,70,0,0,0,0,5,4,1,14,1,2,1, 24,1,14,1,10,1,10,1,8,1,6,2,6,1,6,1, 10,2,6,1,4,2,8,1,12,1,16,1,8,1,10,1, @@ -2166,7 +2166,7 @@ 0,146,2,113,4,83,0,114,4,0,0,0,41,1,114,92, 0,0,0,41,2,114,24,0,0,0,90,2,102,110,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,250,9,60, - 115,101,116,99,111,109,112,62,28,5,0,0,115,2,0,0, + 115,101,116,99,111,109,112,62,29,5,0,0,115,2,0,0, 0,6,0,122,41,70,105,108,101,70,105,110,100,101,114,46, 95,102,105,108,108,95,99,97,99,104,101,46,60,108,111,99, 97,108,115,62,46,60,115,101,116,99,111,109,112,62,78,41, @@ -2183,7 +2183,7 @@ 111,110,116,101,110,116,115,114,244,0,0,0,114,102,0,0, 0,114,234,0,0,0,114,222,0,0,0,90,8,110,101,119, 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,12,1,0,0,255,4,0,0,115,34,0, + 6,0,0,0,114,12,1,0,0,0,5,0,0,115,34,0, 0,0,0,2,6,1,2,1,22,1,20,3,10,3,12,1, 12,7,6,1,10,1,16,1,4,1,18,2,4,1,14,1, 6,1,12,1,122,22,70,105,108,101,70,105,110,100,101,114, @@ -2211,7 +2211,7 @@ 32,32,32,99,1,0,0,0,0,0,0,0,1,0,0,0, 4,0,0,0,19,0,0,0,115,34,0,0,0,116,0,124, 0,131,1,115,20,116,1,100,1,124,0,100,2,141,2,130, - 1,136,0,124,0,102,1,136,1,152,2,142,0,83,0,41, + 1,136,0,124,0,102,1,136,1,158,2,142,0,83,0,41, 3,122,45,80,97,116,104,32,104,111,111,107,32,102,111,114, 32,105,109,112,111,114,116,108,105,98,46,109,97,99,104,105, 110,101,114,121,46,70,105,108,101,70,105,110,100,101,114,46, @@ -2221,7 +2221,7 @@ 0,0,0,41,1,114,37,0,0,0,41,2,114,168,0,0, 0,114,11,1,0,0,114,4,0,0,0,114,6,0,0,0, 218,24,112,97,116,104,95,104,111,111,107,95,102,111,114,95, - 70,105,108,101,70,105,110,100,101,114,40,5,0,0,115,6, + 70,105,108,101,70,105,110,100,101,114,41,5,0,0,115,6, 0,0,0,0,2,8,1,12,1,122,54,70,105,108,101,70, 105,110,100,101,114,46,112,97,116,104,95,104,111,111,107,46, 60,108,111,99,97,108,115,62,46,112,97,116,104,95,104,111, @@ -2229,7 +2229,7 @@ 114,114,4,0,0,0,41,3,114,168,0,0,0,114,11,1, 0,0,114,17,1,0,0,114,4,0,0,0,41,2,114,168, 0,0,0,114,11,1,0,0,114,6,0,0,0,218,9,112, - 97,116,104,95,104,111,111,107,30,5,0,0,115,4,0,0, + 97,116,104,95,104,111,111,107,31,5,0,0,115,4,0,0, 0,0,10,14,6,122,20,70,105,108,101,70,105,110,100,101, 114,46,112,97,116,104,95,104,111,111,107,99,1,0,0,0, 0,0,0,0,1,0,0,0,2,0,0,0,67,0,0,0, @@ -2237,7 +2237,7 @@ 0,41,2,78,122,16,70,105,108,101,70,105,110,100,101,114, 40,123,33,114,125,41,41,2,114,50,0,0,0,114,37,0, 0,0,41,1,114,104,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,243,0,0,0,48,5,0, + 0,0,0,114,6,0,0,0,114,243,0,0,0,49,5,0, 0,115,2,0,0,0,0,1,122,19,70,105,108,101,70,105, 110,100,101,114,46,95,95,114,101,112,114,95,95,41,1,78, 41,15,114,109,0,0,0,114,108,0,0,0,114,110,0,0, @@ -2246,7 +2246,7 @@ 4,1,0,0,114,178,0,0,0,114,12,1,0,0,114,180, 0,0,0,114,18,1,0,0,114,243,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,5,1,0,0,161,4,0,0,115,20,0,0,0,8, + 0,114,5,1,0,0,162,4,0,0,115,20,0,0,0,8, 7,4,2,8,14,8,4,4,2,8,12,8,5,10,48,8, 31,12,18,114,5,1,0,0,99,4,0,0,0,0,0,0, 0,6,0,0,0,11,0,0,0,67,0,0,0,115,146,0, @@ -2269,7 +2269,7 @@ 104,110,97,109,101,90,9,99,112,97,116,104,110,97,109,101, 114,124,0,0,0,114,162,0,0,0,114,4,0,0,0,114, 4,0,0,0,114,6,0,0,0,218,14,95,102,105,120,95, - 117,112,95,109,111,100,117,108,101,54,5,0,0,115,34,0, + 117,112,95,109,111,100,117,108,101,55,5,0,0,115,34,0, 0,0,0,2,10,1,10,1,4,1,4,1,8,1,8,1, 12,2,10,1,4,1,14,1,2,1,8,1,8,1,8,1, 12,1,14,2,114,23,1,0,0,99,0,0,0,0,0,0, @@ -2289,7 +2289,7 @@ 41,3,90,10,101,120,116,101,110,115,105,111,110,115,90,6, 115,111,117,114,99,101,90,8,98,121,116,101,99,111,100,101, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 159,0,0,0,77,5,0,0,115,8,0,0,0,0,5,12, + 159,0,0,0,78,5,0,0,115,8,0,0,0,0,5,12, 1,8,1,8,1,114,159,0,0,0,99,1,0,0,0,0, 0,0,0,12,0,0,0,12,0,0,0,67,0,0,0,115, 188,1,0,0,124,0,97,0,116,0,106,1,97,1,116,0, @@ -2341,7 +2341,7 @@ 1,100,0,107,2,86,0,1,0,113,2,100,1,83,0,41, 2,114,31,0,0,0,78,41,1,114,33,0,0,0,41,2, 114,24,0,0,0,114,81,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,224,0,0,0,113,5, + 4,0,0,0,114,6,0,0,0,114,224,0,0,0,114,5, 0,0,115,2,0,0,0,4,0,122,25,95,115,101,116,117, 112,46,60,108,111,99,97,108,115,62,46,60,103,101,110,101, 120,112,114,62,114,62,0,0,0,122,30,105,109,112,111,114, @@ -2371,7 +2371,7 @@ 14,119,101,97,107,114,101,102,95,109,111,100,117,108,101,90, 13,119,105,110,114,101,103,95,109,111,100,117,108,101,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,218,6,95, - 115,101,116,117,112,88,5,0,0,115,82,0,0,0,0,8, + 115,101,116,117,112,89,5,0,0,115,82,0,0,0,0,8, 4,1,6,1,6,3,10,1,10,1,10,1,12,2,10,1, 16,3,22,1,14,2,22,1,8,1,10,1,10,1,4,2, 2,1,10,1,6,1,14,1,12,2,8,1,12,1,12,1, @@ -2394,7 +2394,7 @@ 0,0,0,41,2,114,31,1,0,0,90,17,115,117,112,112, 111,114,116,101,100,95,108,111,97,100,101,114,115,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,8,95,105, - 110,115,116,97,108,108,156,5,0,0,115,12,0,0,0,0, + 110,115,116,97,108,108,157,5,0,0,115,12,0,0,0,0, 2,8,1,6,1,20,1,10,1,12,1,114,34,1,0,0, 41,1,114,0,0,0,0,41,2,114,1,0,0,0,114,2, 0,0,0,41,1,114,49,0,0,0,41,1,78,41,3,78, @@ -2428,7 +2428,7 @@ 0,114,6,0,0,0,218,8,60,109,111,100,117,108,101,62, 8,0,0,0,115,108,0,0,0,4,16,4,1,4,1,2, 1,6,3,8,17,8,5,8,5,8,6,8,12,8,10,8, - 9,8,5,8,7,10,22,10,121,16,1,12,2,4,1,4, + 9,8,5,8,7,10,22,10,122,16,1,12,2,4,1,4, 2,6,2,6,2,8,2,16,45,8,34,8,19,8,12,8, 12,8,28,8,17,10,55,10,12,10,10,8,14,6,3,4, 1,14,67,14,64,14,29,16,110,14,41,18,45,18,16,4, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -157,7 +157,7 @@ &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&_unknown_opcode, + &&TARGET_BUILD_TUPLE_UNPACK_WITH_CALL, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 03:38:26 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 07:38:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161002073815.76001.7209.86E9B566@psf.io> https://hg.python.org/cpython/rev/818e5416ab39 changeset: 104232:818e5416ab39 parent: 104228:bde594cd8369 parent: 104231:d619246e5eb7 user: Serhiy Storchaka date: Sun Oct 02 10:37:54 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 03:38:26 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 07:38:26 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjU3?= =?utf-8?q?=3A_Improved_error_message_when_pass_a_non-iterable_as?= Message-ID: <20161002073814.82256.80654.C246733F@psf.io> https://hg.python.org/cpython/rev/88b319dfc909 changeset: 104227:88b319dfc909 branch: 3.6 parent: 104225:c4937d066a8e user: Serhiy Storchaka date: Sun Oct 02 10:33:46 2016 +0300 summary: Issue #28257: Improved error message when pass a non-iterable as a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL. files: Include/opcode.h | 1 + Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 5 +- Lib/test/test_extcall.py | 10 + Misc/NEWS | 3 + Python/ceval.c | 13 +- Python/compile.c | 4 +- Python/importlib_external.h | 212 +++++++------- Python/opcode_targets.h | 2 +- 9 files changed, 140 insertions(+), 113 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h --- a/Include/opcode.h +++ b/Include/opcode.h @@ -125,6 +125,7 @@ #define FORMAT_VALUE 155 #define BUILD_CONST_KEY_MAP 156 #define BUILD_STRING 157 +#define BUILD_TUPLE_UNPACK_WITH_CALL 158 /* EXCEPT_HANDLER is a special, implicit block type which is created when entering an except handler. It is not an opcode but we define it here diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -238,6 +238,7 @@ # #27985) # Python 3.6b1 3376 (simplify CALL_FUNCTIONs & BUILD_MAP_UNPACK_WITH_CALL) # Python 3.6b1 3377 (set __class__ cell from type.__new__ #23722) +# Python 3.6b2 3378 (add BUILD_TUPLE_UNPACK_WITH_CALL #28257) # # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually @@ -246,7 +247,7 @@ # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3377).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3378).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -196,8 +196,6 @@ def_op('LOAD_CLASSDEREF', 148) hasfree.append(148) -jrel_op('SETUP_ASYNC_WITH', 154) - def_op('EXTENDED_ARG', 144) EXTENDED_ARG = 144 @@ -207,8 +205,11 @@ def_op('BUILD_TUPLE_UNPACK', 152) def_op('BUILD_SET_UNPACK', 153) +jrel_op('SETUP_ASYNC_WITH', 154) + def_op('FORMAT_VALUE', 155) def_op('BUILD_CONST_KEY_MAP', 156) def_op('BUILD_STRING', 157) +def_op('BUILD_TUPLE_UNPACK_WITH_CALL', 158) del def_op, name_op, jrel_op, jabs_op diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -233,6 +233,16 @@ ... TypeError: h() argument after * must be an iterable, not function + >>> h(1, *h) + Traceback (most recent call last): + ... + TypeError: h() argument after * must be an iterable, not function + + >>> h(*[1], *h) + Traceback (most recent call last): + ... + TypeError: h() argument after * must be an iterable, not function + >>> dir(*h) Traceback (most recent call last): ... diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,9 @@ Library ------- +- Issue #28257: Improved error message when pass a non-iterable as + a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL. + - Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2509,9 +2509,10 @@ DISPATCH(); } + TARGET(BUILD_TUPLE_UNPACK_WITH_CALL) TARGET(BUILD_TUPLE_UNPACK) TARGET(BUILD_LIST_UNPACK) { - int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK; + int convert_to_tuple = opcode != BUILD_LIST_UNPACK; Py_ssize_t i; PyObject *sum = PyList_New(0); PyObject *return_value; @@ -2524,6 +2525,16 @@ none_val = _PyList_Extend((PyListObject *)sum, PEEK(i)); if (none_val == NULL) { + if (opcode == BUILD_TUPLE_UNPACK_WITH_CALL && + PyErr_ExceptionMatches(PyExc_TypeError)) { + PyObject *func = PEEK(1 + oparg); + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after * " + "must be an iterable, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + PEEK(i)->ob_type->tp_name); + } Py_DECREF(sum); goto error; } diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -987,9 +987,9 @@ return 1-oparg; case BUILD_LIST_UNPACK: case BUILD_TUPLE_UNPACK: + case BUILD_TUPLE_UNPACK_WITH_CALL: case BUILD_SET_UNPACK: case BUILD_MAP_UNPACK: - return 1 - oparg; case BUILD_MAP_UNPACK_WITH_CALL: return 1 - oparg; case BUILD_MAP: @@ -3549,7 +3549,7 @@ if (nsubargs > 1) { /* If we ended up with more than one stararg, we need to concatenate them into a single sequence. */ - ADDOP_I(c, BUILD_TUPLE_UNPACK, nsubargs); + ADDOP_I(c, BUILD_TUPLE_UNPACK_WITH_CALL, nsubargs); } else if (nsubargs == 0) { ADDOP_I(c, BUILD_TUPLE, 0); diff --git a/Python/importlib_external.h b/Python/importlib_external.h --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -242,7 +242,7 @@ 101,95,97,116,111,109,105,99,106,0,0,0,115,26,0,0, 0,0,5,16,1,6,1,26,1,2,3,14,1,20,1,16, 1,14,1,2,1,14,1,14,1,6,1,114,58,0,0,0, - 105,49,13,0,0,233,2,0,0,0,114,15,0,0,0,115, + 105,50,13,0,0,233,2,0,0,0,114,15,0,0,0,115, 2,0,0,0,13,10,90,11,95,95,112,121,99,97,99,104, 101,95,95,122,4,111,112,116,45,122,3,46,112,121,122,4, 46,112,121,99,78,41,1,218,12,111,112,116,105,109,105,122, @@ -346,7 +346,7 @@ 103,90,15,97,108,109,111,115,116,95,102,105,108,101,110,97, 109,101,114,4,0,0,0,114,4,0,0,0,114,6,0,0, 0,218,17,99,97,99,104,101,95,102,114,111,109,95,115,111, - 117,114,99,101,5,1,0,0,115,48,0,0,0,0,18,8, + 117,114,99,101,6,1,0,0,115,48,0,0,0,0,18,8, 1,6,1,6,1,8,1,4,1,8,1,12,1,10,1,12, 1,16,1,8,1,8,1,8,1,24,1,8,1,12,1,6, 2,8,1,8,1,8,1,8,1,14,1,14,1,114,83,0, @@ -420,7 +420,7 @@ 112,116,95,108,101,118,101,108,90,13,98,97,115,101,95,102, 105,108,101,110,97,109,101,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,17,115,111,117,114,99,101,95,102, - 114,111,109,95,99,97,99,104,101,50,1,0,0,115,46,0, + 114,111,109,95,99,97,99,104,101,51,1,0,0,115,46,0, 0,0,0,9,12,1,8,1,10,1,12,1,12,1,8,1, 6,1,10,1,10,1,8,1,6,1,10,1,8,1,16,1, 10,1,6,1,8,1,16,1,8,1,6,1,8,1,14,1, @@ -456,7 +456,7 @@ 115,105,111,110,218,11,115,111,117,114,99,101,95,112,97,116, 104,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, 218,15,95,103,101,116,95,115,111,117,114,99,101,102,105,108, - 101,84,1,0,0,115,20,0,0,0,0,7,12,1,4,1, + 101,85,1,0,0,115,20,0,0,0,0,7,12,1,4,1, 16,1,26,1,4,1,2,1,12,1,18,1,18,1,114,95, 0,0,0,99,1,0,0,0,0,0,0,0,1,0,0,0, 11,0,0,0,67,0,0,0,115,74,0,0,0,124,0,106, @@ -469,7 +469,7 @@ 0,0,114,83,0,0,0,114,70,0,0,0,114,78,0,0, 0,41,1,218,8,102,105,108,101,110,97,109,101,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,11,95,103, - 101,116,95,99,97,99,104,101,100,103,1,0,0,115,16,0, + 101,116,95,99,97,99,104,101,100,104,1,0,0,115,16,0, 0,0,0,1,14,1,2,1,8,1,14,1,8,1,14,1, 6,2,114,99,0,0,0,99,1,0,0,0,0,0,0,0, 2,0,0,0,11,0,0,0,67,0,0,0,115,52,0,0, @@ -483,7 +483,7 @@ 0,233,128,0,0,0,41,3,114,41,0,0,0,114,43,0, 0,0,114,42,0,0,0,41,2,114,37,0,0,0,114,44, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,10,95,99,97,108,99,95,109,111,100,101,115,1, + 0,0,218,10,95,99,97,108,99,95,109,111,100,101,116,1, 0,0,115,12,0,0,0,0,2,2,1,14,1,14,1,10, 3,8,1,114,101,0,0,0,99,1,0,0,0,0,0,0, 0,3,0,0,0,11,0,0,0,3,0,0,0,115,68,0, @@ -512,7 +512,7 @@ 0,124,1,100,0,107,8,114,16,124,0,106,0,125,1,110, 32,124,0,106,0,124,1,107,3,114,48,116,1,100,1,124, 0,106,0,124,1,102,2,22,0,124,1,100,2,141,2,130, - 1,136,0,124,0,124,1,102,2,124,2,152,2,124,3,142, + 1,136,0,124,0,124,1,102,2,124,2,158,2,124,3,142, 1,83,0,41,3,78,122,30,108,111,97,100,101,114,32,102, 111,114,32,37,115,32,99,97,110,110,111,116,32,104,97,110, 100,108,101,32,37,115,41,1,218,4,110,97,109,101,41,2, @@ -521,7 +521,7 @@ 4,97,114,103,115,90,6,107,119,97,114,103,115,41,1,218, 6,109,101,116,104,111,100,114,4,0,0,0,114,6,0,0, 0,218,19,95,99,104,101,99,107,95,110,97,109,101,95,119, - 114,97,112,112,101,114,135,1,0,0,115,12,0,0,0,0, + 114,97,112,112,101,114,136,1,0,0,115,12,0,0,0,0, 1,8,1,8,1,10,1,4,1,18,1,122,40,95,99,104, 101,99,107,95,110,97,109,101,46,60,108,111,99,97,108,115, 62,46,95,99,104,101,99,107,95,110,97,109,101,95,119,114, @@ -540,7 +540,7 @@ 95,95,100,105,99,116,95,95,218,6,117,112,100,97,116,101, 41,3,90,3,110,101,119,90,3,111,108,100,114,55,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,5,95,119,114,97,112,146,1,0,0,115,8,0,0,0, + 218,5,95,119,114,97,112,147,1,0,0,115,8,0,0,0, 0,1,10,1,10,1,22,1,122,26,95,99,104,101,99,107, 95,110,97,109,101,46,60,108,111,99,97,108,115,62,46,95, 119,114,97,112,41,1,78,41,3,218,10,95,98,111,111,116, @@ -548,7 +548,7 @@ 69,114,114,111,114,41,3,114,106,0,0,0,114,107,0,0, 0,114,117,0,0,0,114,4,0,0,0,41,1,114,106,0, 0,0,114,6,0,0,0,218,11,95,99,104,101,99,107,95, - 110,97,109,101,127,1,0,0,115,14,0,0,0,0,8,14, + 110,97,109,101,128,1,0,0,115,14,0,0,0,0,8,14, 7,2,1,10,1,14,2,14,5,10,1,114,120,0,0,0, 99,2,0,0,0,0,0,0,0,5,0,0,0,4,0,0, 0,67,0,0,0,115,60,0,0,0,124,0,106,0,124,1, @@ -576,7 +576,7 @@ 97,100,101,114,218,8,112,111,114,116,105,111,110,115,218,3, 109,115,103,114,4,0,0,0,114,4,0,0,0,114,6,0, 0,0,218,17,95,102,105,110,100,95,109,111,100,117,108,101, - 95,115,104,105,109,155,1,0,0,115,10,0,0,0,0,10, + 95,115,104,105,109,156,1,0,0,115,10,0,0,0,0,10, 14,1,16,1,4,1,22,1,114,127,0,0,0,99,4,0, 0,0,0,0,0,0,11,0,0,0,22,0,0,0,67,0, 0,0,115,136,1,0,0,105,0,125,4,124,2,100,1,107, @@ -656,7 +656,7 @@ 218,11,115,111,117,114,99,101,95,115,105,122,101,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,25,95,118, 97,108,105,100,97,116,101,95,98,121,116,101,99,111,100,101, - 95,104,101,97,100,101,114,172,1,0,0,115,76,0,0,0, + 95,104,101,97,100,101,114,173,1,0,0,115,76,0,0,0, 0,11,4,1,8,1,10,3,4,1,8,1,8,1,12,1, 12,1,12,1,8,1,12,1,12,1,14,1,12,1,10,1, 12,1,10,1,12,1,10,1,12,1,8,1,10,1,2,1, @@ -685,7 +685,7 @@ 41,5,114,56,0,0,0,114,102,0,0,0,114,93,0,0, 0,114,94,0,0,0,218,4,99,111,100,101,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,218,17,95,99,111, - 109,112,105,108,101,95,98,121,116,101,99,111,100,101,227,1, + 109,112,105,108,101,95,98,121,116,101,99,111,100,101,228,1, 0,0,115,16,0,0,0,0,2,10,1,10,1,12,1,8, 1,12,1,6,2,10,1,114,145,0,0,0,114,62,0,0, 0,99,3,0,0,0,0,0,0,0,4,0,0,0,3,0, @@ -704,7 +704,7 @@ 112,115,41,4,114,144,0,0,0,114,130,0,0,0,114,138, 0,0,0,114,56,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,6,0,0,0,218,17,95,99,111,100,101,95,116, - 111,95,98,121,116,101,99,111,100,101,239,1,0,0,115,10, + 111,95,98,121,116,101,99,111,100,101,240,1,0,0,115,10, 0,0,0,0,3,8,1,14,1,14,1,16,1,114,148,0, 0,0,99,1,0,0,0,0,0,0,0,5,0,0,0,4, 0,0,0,67,0,0,0,115,62,0,0,0,100,1,100,2, @@ -731,7 +731,7 @@ 110,101,218,8,101,110,99,111,100,105,110,103,90,15,110,101, 119,108,105,110,101,95,100,101,99,111,100,101,114,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,13,100,101, - 99,111,100,101,95,115,111,117,114,99,101,249,1,0,0,115, + 99,111,100,101,95,115,111,117,114,99,101,250,1,0,0,115, 10,0,0,0,0,5,8,1,12,1,10,1,12,1,114,153, 0,0,0,41,2,114,124,0,0,0,218,26,115,117,98,109, 111,100,117,108,101,95,115,101,97,114,99,104,95,108,111,99, @@ -793,7 +793,7 @@ 0,0,0,90,7,100,105,114,110,97,109,101,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,218,23,115,112,101, 99,95,102,114,111,109,95,102,105,108,101,95,108,111,99,97, - 116,105,111,110,10,2,0,0,115,62,0,0,0,0,12,8, + 116,105,111,110,11,2,0,0,115,62,0,0,0,0,12,8, 4,4,1,10,2,2,1,14,1,14,1,8,2,10,8,16, 1,6,3,8,1,16,1,14,1,10,1,6,1,6,2,4, 3,8,2,10,1,2,1,14,1,14,1,6,2,4,1,8, @@ -829,7 +829,7 @@ 18,72,75,69,89,95,76,79,67,65,76,95,77,65,67,72, 73,78,69,41,2,218,3,99,108,115,114,5,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,14, - 95,111,112,101,110,95,114,101,103,105,115,116,114,121,90,2, + 95,111,112,101,110,95,114,101,103,105,115,116,114,121,91,2, 0,0,115,8,0,0,0,0,2,2,1,14,1,14,1,122, 36,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, 70,105,110,100,101,114,46,95,111,112,101,110,95,114,101,103, @@ -855,7 +855,7 @@ 121,95,107,101,121,114,5,0,0,0,90,4,104,107,101,121, 218,8,102,105,108,101,112,97,116,104,114,4,0,0,0,114, 4,0,0,0,114,6,0,0,0,218,16,95,115,101,97,114, - 99,104,95,114,101,103,105,115,116,114,121,97,2,0,0,115, + 99,104,95,114,101,103,105,115,116,114,121,98,2,0,0,115, 22,0,0,0,0,2,6,1,8,2,6,1,6,1,22,1, 2,1,12,1,26,1,14,1,6,1,122,38,87,105,110,100, 111,119,115,82,101,103,105,115,116,114,121,70,105,110,100,101, @@ -877,7 +877,7 @@ 0,0,114,37,0,0,0,218,6,116,97,114,103,101,116,114, 174,0,0,0,114,124,0,0,0,114,164,0,0,0,114,162, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,9,102,105,110,100,95,115,112,101,99,112,2,0, + 0,0,218,9,102,105,110,100,95,115,112,101,99,113,2,0, 0,115,26,0,0,0,0,2,10,1,8,1,4,1,2,1, 12,1,14,1,6,1,16,1,14,1,6,1,8,1,8,1, 122,31,87,105,110,100,111,119,115,82,101,103,105,115,116,114, @@ -896,7 +896,7 @@ 41,2,114,178,0,0,0,114,124,0,0,0,41,4,114,168, 0,0,0,114,123,0,0,0,114,37,0,0,0,114,162,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,218,11,102,105,110,100,95,109,111,100,117,108,101,128,2, + 0,218,11,102,105,110,100,95,109,111,100,117,108,101,129,2, 0,0,115,8,0,0,0,0,7,12,1,8,1,8,2,122, 33,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, 70,105,110,100,101,114,46,102,105,110,100,95,109,111,100,117, @@ -906,7 +906,7 @@ 99,108,97,115,115,109,101,116,104,111,100,114,169,0,0,0, 114,175,0,0,0,114,178,0,0,0,114,179,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,166,0,0,0,78,2,0,0,115,20,0,0, + 0,0,0,114,166,0,0,0,79,2,0,0,115,20,0,0, 0,8,2,4,3,4,3,4,2,4,2,12,7,12,15,2, 1,12,15,2,1,114,166,0,0,0,99,0,0,0,0,0, 0,0,0,0,0,0,0,2,0,0,0,64,0,0,0,115, @@ -941,7 +941,7 @@ 114,123,0,0,0,114,98,0,0,0,90,13,102,105,108,101, 110,97,109,101,95,98,97,115,101,90,9,116,97,105,108,95, 110,97,109,101,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,157,0,0,0,147,2,0,0,115,8,0,0, + 0,0,0,114,157,0,0,0,148,2,0,0,115,8,0,0, 0,0,3,18,1,16,1,14,1,122,24,95,76,111,97,100, 101,114,66,97,115,105,99,115,46,105,115,95,112,97,99,107, 97,103,101,99,2,0,0,0,0,0,0,0,2,0,0,0, @@ -951,7 +951,7 @@ 111,100,117,108,101,32,99,114,101,97,116,105,111,110,46,78, 114,4,0,0,0,41,2,114,104,0,0,0,114,162,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,13,99,114,101,97,116,101,95,109,111,100,117,108,101,155, + 218,13,99,114,101,97,116,101,95,109,111,100,117,108,101,156, 2,0,0,115,0,0,0,0,122,27,95,76,111,97,100,101, 114,66,97,115,105,99,115,46,99,114,101,97,116,101,95,109, 111,100,117,108,101,99,2,0,0,0,0,0,0,0,3,0, @@ -971,7 +971,7 @@ 218,4,101,120,101,99,114,115,0,0,0,41,3,114,104,0, 0,0,218,6,109,111,100,117,108,101,114,144,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,11, - 101,120,101,99,95,109,111,100,117,108,101,158,2,0,0,115, + 101,120,101,99,95,109,111,100,117,108,101,159,2,0,0,115, 10,0,0,0,0,2,12,1,8,1,6,1,10,1,122,25, 95,76,111,97,100,101,114,66,97,115,105,99,115,46,101,120, 101,99,95,109,111,100,117,108,101,99,2,0,0,0,0,0, @@ -982,14 +982,14 @@ 118,0,0,0,218,17,95,108,111,97,100,95,109,111,100,117, 108,101,95,115,104,105,109,41,2,114,104,0,0,0,114,123, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,11,108,111,97,100,95,109,111,100,117,108,101,166, + 0,0,218,11,108,111,97,100,95,109,111,100,117,108,101,167, 2,0,0,115,2,0,0,0,0,2,122,25,95,76,111,97, 100,101,114,66,97,115,105,99,115,46,108,111,97,100,95,109, 111,100,117,108,101,78,41,8,114,109,0,0,0,114,108,0, 0,0,114,110,0,0,0,114,111,0,0,0,114,157,0,0, 0,114,183,0,0,0,114,188,0,0,0,114,190,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,181,0,0,0,142,2,0,0,115,10,0, + 6,0,0,0,114,181,0,0,0,143,2,0,0,115,10,0, 0,0,8,3,4,2,8,8,8,3,8,8,114,181,0,0, 0,99,0,0,0,0,0,0,0,0,0,0,0,0,3,0, 0,0,64,0,0,0,115,74,0,0,0,101,0,90,1,100, @@ -1015,7 +1015,7 @@ 218,7,73,79,69,114,114,111,114,41,2,114,104,0,0,0, 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, 6,0,0,0,218,10,112,97,116,104,95,109,116,105,109,101, - 173,2,0,0,115,2,0,0,0,0,6,122,23,83,111,117, + 174,2,0,0,115,2,0,0,0,0,6,122,23,83,111,117, 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,109, 116,105,109,101,99,2,0,0,0,0,0,0,0,2,0,0, 0,3,0,0,0,67,0,0,0,115,14,0,0,0,100,1, @@ -1050,7 +1050,7 @@ 0,0,41,1,114,193,0,0,0,41,2,114,104,0,0,0, 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, 6,0,0,0,218,10,112,97,116,104,95,115,116,97,116,115, - 181,2,0,0,115,2,0,0,0,0,11,122,23,83,111,117, + 182,2,0,0,115,2,0,0,0,0,11,122,23,83,111,117, 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,115, 116,97,116,115,99,4,0,0,0,0,0,0,0,4,0,0, 0,3,0,0,0,67,0,0,0,115,12,0,0,0,124,0, @@ -1073,7 +1073,7 @@ 114,104,0,0,0,114,94,0,0,0,90,10,99,97,99,104, 101,95,112,97,116,104,114,56,0,0,0,114,4,0,0,0, 114,4,0,0,0,114,6,0,0,0,218,15,95,99,97,99, - 104,101,95,98,121,116,101,99,111,100,101,194,2,0,0,115, + 104,101,95,98,121,116,101,99,111,100,101,195,2,0,0,115, 2,0,0,0,0,8,122,28,83,111,117,114,99,101,76,111, 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, 99,111,100,101,99,3,0,0,0,0,0,0,0,3,0,0, @@ -1090,7 +1090,7 @@ 101,115,46,10,32,32,32,32,32,32,32,32,78,114,4,0, 0,0,41,3,114,104,0,0,0,114,37,0,0,0,114,56, 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,195,0,0,0,204,2,0,0,115,0,0,0,0, + 0,0,114,195,0,0,0,205,2,0,0,115,0,0,0,0, 122,21,83,111,117,114,99,101,76,111,97,100,101,114,46,115, 101,116,95,100,97,116,97,99,2,0,0,0,0,0,0,0, 5,0,0,0,16,0,0,0,67,0,0,0,115,82,0,0, @@ -1111,7 +1111,7 @@ 0,0,0,114,123,0,0,0,114,37,0,0,0,114,151,0, 0,0,218,3,101,120,99,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,10,103,101,116,95,115,111,117,114, - 99,101,211,2,0,0,115,14,0,0,0,0,2,10,1,2, + 99,101,212,2,0,0,115,14,0,0,0,0,2,10,1,2, 1,14,1,16,1,4,1,28,1,122,23,83,111,117,114,99, 101,76,111,97,100,101,114,46,103,101,116,95,115,111,117,114, 99,101,114,31,0,0,0,41,1,218,9,95,111,112,116,105, @@ -1132,7 +1132,7 @@ 0,218,7,99,111,109,112,105,108,101,41,4,114,104,0,0, 0,114,56,0,0,0,114,37,0,0,0,114,200,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, - 14,115,111,117,114,99,101,95,116,111,95,99,111,100,101,221, + 14,115,111,117,114,99,101,95,116,111,95,99,111,100,101,222, 2,0,0,115,4,0,0,0,0,5,12,1,122,27,83,111, 117,114,99,101,76,111,97,100,101,114,46,115,111,117,114,99, 101,95,116,111,95,99,111,100,101,99,2,0,0,0,0,0, @@ -1189,7 +1189,7 @@ 114,56,0,0,0,218,10,98,121,116,101,115,95,100,97,116, 97,114,151,0,0,0,90,11,99,111,100,101,95,111,98,106, 101,99,116,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,184,0,0,0,229,2,0,0,115,78,0,0,0, + 0,0,114,184,0,0,0,230,2,0,0,115,78,0,0,0, 0,7,10,1,4,1,2,1,12,1,14,1,10,2,2,1, 14,1,14,1,6,2,12,1,2,1,14,1,14,1,6,2, 2,1,4,1,4,1,12,1,18,1,6,2,8,1,6,1, @@ -1201,7 +1201,7 @@ 0,114,194,0,0,0,114,196,0,0,0,114,195,0,0,0, 114,199,0,0,0,114,203,0,0,0,114,184,0,0,0,114, 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,191,0,0,0,171,2,0,0,115,14,0,0, + 0,0,0,114,191,0,0,0,172,2,0,0,115,14,0,0, 0,8,2,8,8,8,13,8,10,8,7,8,10,14,8,114, 191,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, 0,4,0,0,0,0,0,0,0,115,80,0,0,0,101,0, @@ -1228,7 +1228,7 @@ 2,114,102,0,0,0,114,37,0,0,0,41,3,114,104,0, 0,0,114,123,0,0,0,114,37,0,0,0,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,114,182,0,0,0, - 30,3,0,0,115,4,0,0,0,0,3,6,1,122,19,70, + 31,3,0,0,115,4,0,0,0,0,3,6,1,122,19,70, 105,108,101,76,111,97,100,101,114,46,95,95,105,110,105,116, 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, 0,0,0,67,0,0,0,115,24,0,0,0,124,0,106,0, @@ -1236,7 +1236,7 @@ 107,2,83,0,41,1,78,41,2,218,9,95,95,99,108,97, 115,115,95,95,114,115,0,0,0,41,2,114,104,0,0,0, 218,5,111,116,104,101,114,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,6,95,95,101,113,95,95,36,3, + 0,114,6,0,0,0,218,6,95,95,101,113,95,95,37,3, 0,0,115,4,0,0,0,0,1,12,1,122,17,70,105,108, 101,76,111,97,100,101,114,46,95,95,101,113,95,95,99,1, 0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,67, @@ -1245,7 +1245,7 @@ 3,218,4,104,97,115,104,114,102,0,0,0,114,37,0,0, 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,6,0,0,0,218,8,95,95,104,97,115,104,95, - 95,40,3,0,0,115,2,0,0,0,0,1,122,19,70,105, + 95,41,3,0,0,115,2,0,0,0,0,1,122,19,70,105, 108,101,76,111,97,100,101,114,46,95,95,104,97,115,104,95, 95,99,2,0,0,0,0,0,0,0,2,0,0,0,3,0, 0,0,3,0,0,0,115,16,0,0,0,116,0,116,1,124, @@ -1259,7 +1259,7 @@ 32,32,32,41,3,218,5,115,117,112,101,114,114,207,0,0, 0,114,190,0,0,0,41,2,114,104,0,0,0,114,123,0, 0,0,41,1,114,208,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,190,0,0,0,43,3,0,0,115,2,0,0, + 0,0,0,114,190,0,0,0,44,3,0,0,115,2,0,0, 0,0,10,122,22,70,105,108,101,76,111,97,100,101,114,46, 108,111,97,100,95,109,111,100,117,108,101,99,2,0,0,0, 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, @@ -1270,7 +1270,7 @@ 101,32,102,105,110,100,101,114,46,41,1,114,37,0,0,0, 41,2,114,104,0,0,0,114,123,0,0,0,114,4,0,0, 0,114,4,0,0,0,114,6,0,0,0,114,155,0,0,0, - 55,3,0,0,115,2,0,0,0,0,3,122,23,70,105,108, + 56,3,0,0,115,2,0,0,0,0,3,122,23,70,105,108, 101,76,111,97,100,101,114,46,103,101,116,95,102,105,108,101, 110,97,109,101,99,2,0,0,0,0,0,0,0,3,0,0, 0,9,0,0,0,67,0,0,0,115,32,0,0,0,116,0, @@ -1282,7 +1282,7 @@ 52,0,0,0,114,53,0,0,0,90,4,114,101,97,100,41, 3,114,104,0,0,0,114,37,0,0,0,114,57,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 197,0,0,0,60,3,0,0,115,4,0,0,0,0,2,14, + 197,0,0,0,61,3,0,0,115,4,0,0,0,0,2,14, 1,122,19,70,105,108,101,76,111,97,100,101,114,46,103,101, 116,95,100,97,116,97,78,41,12,114,109,0,0,0,114,108, 0,0,0,114,110,0,0,0,114,111,0,0,0,114,182,0, @@ -1290,7 +1290,7 @@ 0,114,190,0,0,0,114,155,0,0,0,114,197,0,0,0, 90,13,95,95,99,108,97,115,115,99,101,108,108,95,95,114, 4,0,0,0,114,4,0,0,0,41,1,114,208,0,0,0, - 114,6,0,0,0,114,207,0,0,0,25,3,0,0,115,14, + 114,6,0,0,0,114,207,0,0,0,26,3,0,0,115,14, 0,0,0,8,3,4,2,8,6,8,4,8,3,16,12,12, 5,114,207,0,0,0,99,0,0,0,0,0,0,0,0,0, 0,0,0,3,0,0,0,64,0,0,0,115,46,0,0,0, @@ -1312,7 +1312,7 @@ 116,105,109,101,90,7,115,116,95,115,105,122,101,41,3,114, 104,0,0,0,114,37,0,0,0,114,205,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,194,0, - 0,0,70,3,0,0,115,4,0,0,0,0,2,8,1,122, + 0,0,71,3,0,0,115,4,0,0,0,0,2,8,1,122, 27,83,111,117,114,99,101,70,105,108,101,76,111,97,100,101, 114,46,112,97,116,104,95,115,116,97,116,115,99,4,0,0, 0,0,0,0,0,5,0,0,0,5,0,0,0,67,0,0, @@ -1322,7 +1322,7 @@ 0,114,195,0,0,0,41,5,114,104,0,0,0,114,94,0, 0,0,114,93,0,0,0,114,56,0,0,0,114,44,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,196,0,0,0,75,3,0,0,115,4,0,0,0,0,2, + 114,196,0,0,0,76,3,0,0,115,4,0,0,0,0,2, 8,1,122,32,83,111,117,114,99,101,70,105,108,101,76,111, 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, 99,111,100,101,105,182,1,0,0,41,1,114,217,0,0,0, @@ -1357,7 +1357,7 @@ 0,218,6,112,97,114,101,110,116,114,98,0,0,0,114,29, 0,0,0,114,25,0,0,0,114,198,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,114,195,0,0, - 0,80,3,0,0,115,42,0,0,0,0,2,12,1,4,2, + 0,81,3,0,0,115,42,0,0,0,0,2,12,1,4,2, 16,1,12,1,14,2,14,1,10,1,2,1,14,1,14,2, 6,1,16,3,6,1,8,1,20,1,2,1,12,1,16,1, 16,2,8,1,122,25,83,111,117,114,99,101,70,105,108,101, @@ -1365,7 +1365,7 @@ 41,7,114,109,0,0,0,114,108,0,0,0,114,110,0,0, 0,114,111,0,0,0,114,194,0,0,0,114,196,0,0,0, 114,195,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,215,0,0,0,66,3, + 4,0,0,0,114,6,0,0,0,114,215,0,0,0,67,3, 0,0,115,8,0,0,0,8,2,4,2,8,5,8,5,114, 215,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, 0,2,0,0,0,64,0,0,0,115,32,0,0,0,101,0, @@ -1385,7 +1385,7 @@ 0,114,197,0,0,0,114,139,0,0,0,114,145,0,0,0, 41,5,114,104,0,0,0,114,123,0,0,0,114,37,0,0, 0,114,56,0,0,0,114,206,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,115, + 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,116, 3,0,0,115,8,0,0,0,0,1,10,1,10,1,14,1, 122,29,83,111,117,114,99,101,108,101,115,115,70,105,108,101, 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, @@ -1395,14 +1395,14 @@ 116,104,101,114,101,32,105,115,32,110,111,32,115,111,117,114, 99,101,32,99,111,100,101,46,78,114,4,0,0,0,41,2, 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,199,0,0,0,121,3, + 4,0,0,0,114,6,0,0,0,114,199,0,0,0,122,3, 0,0,115,2,0,0,0,0,2,122,31,83,111,117,114,99, 101,108,101,115,115,70,105,108,101,76,111,97,100,101,114,46, 103,101,116,95,115,111,117,114,99,101,78,41,6,114,109,0, 0,0,114,108,0,0,0,114,110,0,0,0,114,111,0,0, 0,114,184,0,0,0,114,199,0,0,0,114,4,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 220,0,0,0,111,3,0,0,115,6,0,0,0,8,2,4, + 220,0,0,0,112,3,0,0,115,6,0,0,0,8,2,4, 2,8,6,114,220,0,0,0,99,0,0,0,0,0,0,0, 0,0,0,0,0,3,0,0,0,64,0,0,0,115,92,0, 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, @@ -1424,7 +1424,7 @@ 78,41,2,114,102,0,0,0,114,37,0,0,0,41,3,114, 104,0,0,0,114,102,0,0,0,114,37,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,182,0, - 0,0,138,3,0,0,115,4,0,0,0,0,1,6,1,122, + 0,0,139,3,0,0,115,4,0,0,0,0,1,6,1,122, 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, 97,100,101,114,46,95,95,105,110,105,116,95,95,99,2,0, 0,0,0,0,0,0,2,0,0,0,2,0,0,0,67,0, @@ -1432,7 +1432,7 @@ 2,111,22,124,0,106,1,124,1,106,1,107,2,83,0,41, 1,78,41,2,114,208,0,0,0,114,115,0,0,0,41,2, 114,104,0,0,0,114,209,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,210,0,0,0,142,3, + 4,0,0,0,114,6,0,0,0,114,210,0,0,0,143,3, 0,0,115,4,0,0,0,0,1,12,1,122,26,69,120,116, 101,110,115,105,111,110,70,105,108,101,76,111,97,100,101,114, 46,95,95,101,113,95,95,99,1,0,0,0,0,0,0,0, @@ -1441,7 +1441,7 @@ 1,65,0,83,0,41,1,78,41,3,114,211,0,0,0,114, 102,0,0,0,114,37,0,0,0,41,1,114,104,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 212,0,0,0,146,3,0,0,115,2,0,0,0,0,1,122, + 212,0,0,0,147,3,0,0,115,2,0,0,0,0,1,122, 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, 97,100,101,114,46,95,95,104,97,115,104,95,95,99,2,0, 0,0,0,0,0,0,3,0,0,0,4,0,0,0,67,0, @@ -1458,7 +1458,7 @@ 0,0,0,114,102,0,0,0,114,37,0,0,0,41,3,114, 104,0,0,0,114,162,0,0,0,114,187,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,183,0, - 0,0,149,3,0,0,115,10,0,0,0,0,2,4,1,10, + 0,0,150,3,0,0,115,10,0,0,0,0,2,4,1,10, 1,6,1,12,1,122,33,69,120,116,101,110,115,105,111,110, 70,105,108,101,76,111,97,100,101,114,46,99,114,101,97,116, 101,95,109,111,100,117,108,101,99,2,0,0,0,0,0,0, @@ -1475,7 +1475,7 @@ 105,99,114,133,0,0,0,114,102,0,0,0,114,37,0,0, 0,41,2,114,104,0,0,0,114,187,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,114,188,0,0, - 0,157,3,0,0,115,6,0,0,0,0,2,14,1,6,1, + 0,158,3,0,0,115,6,0,0,0,0,2,14,1,6,1, 122,31,69,120,116,101,110,115,105,111,110,70,105,108,101,76, 111,97,100,101,114,46,101,120,101,99,95,109,111,100,117,108, 101,99,2,0,0,0,0,0,0,0,2,0,0,0,4,0, @@ -1492,7 +1492,7 @@ 182,0,0,0,78,114,4,0,0,0,41,2,114,24,0,0, 0,218,6,115,117,102,102,105,120,41,1,218,9,102,105,108, 101,95,110,97,109,101,114,4,0,0,0,114,6,0,0,0, - 250,9,60,103,101,110,101,120,112,114,62,166,3,0,0,115, + 250,9,60,103,101,110,101,120,112,114,62,167,3,0,0,115, 2,0,0,0,4,1,122,49,69,120,116,101,110,115,105,111, 110,70,105,108,101,76,111,97,100,101,114,46,105,115,95,112, 97,99,107,97,103,101,46,60,108,111,99,97,108,115,62,46, @@ -1501,7 +1501,7 @@ 78,83,73,79,78,95,83,85,70,70,73,88,69,83,41,2, 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,41, 1,114,223,0,0,0,114,6,0,0,0,114,157,0,0,0, - 163,3,0,0,115,6,0,0,0,0,2,14,1,12,1,122, + 164,3,0,0,115,6,0,0,0,0,2,14,1,12,1,122, 30,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, 97,100,101,114,46,105,115,95,112,97,99,107,97,103,101,99, 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, @@ -1512,7 +1512,7 @@ 101,32,97,32,99,111,100,101,32,111,98,106,101,99,116,46, 78,114,4,0,0,0,41,2,114,104,0,0,0,114,123,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,184,0,0,0,169,3,0,0,115,2,0,0,0,0, + 0,114,184,0,0,0,170,3,0,0,115,2,0,0,0,0, 2,122,28,69,120,116,101,110,115,105,111,110,70,105,108,101, 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, @@ -1522,7 +1522,7 @@ 115,32,104,97,118,101,32,110,111,32,115,111,117,114,99,101, 32,99,111,100,101,46,78,114,4,0,0,0,41,2,114,104, 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,199,0,0,0,173,3,0,0, + 0,0,114,6,0,0,0,114,199,0,0,0,174,3,0,0, 115,2,0,0,0,0,2,122,30,69,120,116,101,110,115,105, 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, 95,115,111,117,114,99,101,99,2,0,0,0,0,0,0,0, @@ -1533,7 +1533,7 @@ 32,102,111,117,110,100,32,98,121,32,116,104,101,32,102,105, 110,100,101,114,46,41,1,114,37,0,0,0,41,2,114,104, 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,155,0,0,0,177,3,0,0, + 0,0,114,6,0,0,0,114,155,0,0,0,178,3,0,0, 115,2,0,0,0,0,3,122,32,69,120,116,101,110,115,105, 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, 95,102,105,108,101,110,97,109,101,78,41,14,114,109,0,0, @@ -1542,7 +1542,7 @@ 183,0,0,0,114,188,0,0,0,114,157,0,0,0,114,184, 0,0,0,114,199,0,0,0,114,120,0,0,0,114,155,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,114,221,0,0,0,130,3,0,0,115, + 0,114,6,0,0,0,114,221,0,0,0,131,3,0,0,115, 20,0,0,0,8,6,4,2,8,4,8,4,8,3,8,8, 8,6,8,6,8,4,8,4,114,221,0,0,0,99,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,64,0, @@ -1583,7 +1583,7 @@ 12,95,112,97,116,104,95,102,105,110,100,101,114,41,4,114, 104,0,0,0,114,102,0,0,0,114,37,0,0,0,218,11, 112,97,116,104,95,102,105,110,100,101,114,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,182,0,0,0,190, + 114,4,0,0,0,114,6,0,0,0,114,182,0,0,0,191, 3,0,0,115,8,0,0,0,0,1,6,1,6,1,14,1, 122,23,95,78,97,109,101,115,112,97,99,101,80,97,116,104, 46,95,95,105,110,105,116,95,95,99,1,0,0,0,0,0, @@ -1601,7 +1601,7 @@ 0,41,4,114,104,0,0,0,114,219,0,0,0,218,3,100, 111,116,90,2,109,101,114,4,0,0,0,114,4,0,0,0, 114,6,0,0,0,218,23,95,102,105,110,100,95,112,97,114, - 101,110,116,95,112,97,116,104,95,110,97,109,101,115,196,3, + 101,110,116,95,112,97,116,104,95,110,97,109,101,115,197,3, 0,0,115,8,0,0,0,0,2,18,1,8,2,4,3,122, 38,95,78,97,109,101,115,112,97,99,101,80,97,116,104,46, 95,102,105,110,100,95,112,97,114,101,110,116,95,112,97,116, @@ -1614,7 +1614,7 @@ 0,90,18,112,97,114,101,110,116,95,109,111,100,117,108,101, 95,110,97,109,101,90,14,112,97,116,104,95,97,116,116,114, 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,230,0,0,0,206,3,0,0,115,4,0, + 6,0,0,0,114,230,0,0,0,207,3,0,0,115,4,0, 0,0,0,1,12,1,122,31,95,78,97,109,101,115,112,97, 99,101,80,97,116,104,46,95,103,101,116,95,112,97,114,101, 110,116,95,112,97,116,104,99,1,0,0,0,0,0,0,0, @@ -1630,7 +1630,7 @@ 114,104,0,0,0,90,11,112,97,114,101,110,116,95,112,97, 116,104,114,162,0,0,0,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,12,95,114,101,99,97,108,99,117, - 108,97,116,101,210,3,0,0,115,16,0,0,0,0,2,12, + 108,97,116,101,211,3,0,0,115,16,0,0,0,0,2,12, 1,10,1,14,3,18,1,6,1,8,1,6,1,122,27,95, 78,97,109,101,115,112,97,99,101,80,97,116,104,46,95,114, 101,99,97,108,99,117,108,97,116,101,99,1,0,0,0,0, @@ -1639,7 +1639,7 @@ 41,1,78,41,2,218,4,105,116,101,114,114,237,0,0,0, 41,1,114,104,0,0,0,114,4,0,0,0,114,4,0,0, 0,114,6,0,0,0,218,8,95,95,105,116,101,114,95,95, - 223,3,0,0,115,2,0,0,0,0,1,122,23,95,78,97, + 224,3,0,0,115,2,0,0,0,0,1,122,23,95,78,97, 109,101,115,112,97,99,101,80,97,116,104,46,95,95,105,116, 101,114,95,95,99,3,0,0,0,0,0,0,0,3,0,0, 0,3,0,0,0,67,0,0,0,115,14,0,0,0,124,2, @@ -1647,7 +1647,7 @@ 1,114,229,0,0,0,41,3,114,104,0,0,0,218,5,105, 110,100,101,120,114,37,0,0,0,114,4,0,0,0,114,4, 0,0,0,114,6,0,0,0,218,11,95,95,115,101,116,105, - 116,101,109,95,95,226,3,0,0,115,2,0,0,0,0,1, + 116,101,109,95,95,227,3,0,0,115,2,0,0,0,0,1, 122,26,95,78,97,109,101,115,112,97,99,101,80,97,116,104, 46,95,95,115,101,116,105,116,101,109,95,95,99,1,0,0, 0,0,0,0,0,1,0,0,0,2,0,0,0,67,0,0, @@ -1655,7 +1655,7 @@ 83,0,41,1,78,41,2,114,33,0,0,0,114,237,0,0, 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,6,0,0,0,218,7,95,95,108,101,110,95,95, - 229,3,0,0,115,2,0,0,0,0,1,122,22,95,78,97, + 230,3,0,0,115,2,0,0,0,0,1,122,22,95,78,97, 109,101,115,112,97,99,101,80,97,116,104,46,95,95,108,101, 110,95,95,99,1,0,0,0,0,0,0,0,1,0,0,0, 2,0,0,0,67,0,0,0,115,12,0,0,0,100,1,106, @@ -1663,7 +1663,7 @@ 97,109,101,115,112,97,99,101,80,97,116,104,40,123,33,114, 125,41,41,2,114,50,0,0,0,114,229,0,0,0,41,1, 114,104,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,8,95,95,114,101,112,114,95,95,232,3, + 6,0,0,0,218,8,95,95,114,101,112,114,95,95,233,3, 0,0,115,2,0,0,0,0,1,122,23,95,78,97,109,101, 115,112,97,99,101,80,97,116,104,46,95,95,114,101,112,114, 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, @@ -1671,7 +1671,7 @@ 106,0,131,0,107,6,83,0,41,1,78,41,1,114,237,0, 0,0,41,2,114,104,0,0,0,218,4,105,116,101,109,114, 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,12, - 95,95,99,111,110,116,97,105,110,115,95,95,235,3,0,0, + 95,95,99,111,110,116,97,105,110,115,95,95,236,3,0,0, 115,2,0,0,0,0,1,122,27,95,78,97,109,101,115,112, 97,99,101,80,97,116,104,46,95,95,99,111,110,116,97,105, 110,115,95,95,99,2,0,0,0,0,0,0,0,2,0,0, @@ -1679,7 +1679,7 @@ 106,0,106,1,124,1,131,1,1,0,100,0,83,0,41,1, 78,41,2,114,229,0,0,0,114,161,0,0,0,41,2,114, 104,0,0,0,114,244,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,161,0,0,0,238,3,0, + 0,0,0,114,6,0,0,0,114,161,0,0,0,239,3,0, 0,115,2,0,0,0,0,1,122,21,95,78,97,109,101,115, 112,97,99,101,80,97,116,104,46,97,112,112,101,110,100,78, 41,14,114,109,0,0,0,114,108,0,0,0,114,110,0,0, @@ -1688,7 +1688,7 @@ 241,0,0,0,114,242,0,0,0,114,243,0,0,0,114,245, 0,0,0,114,161,0,0,0,114,4,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,114,227,0,0, - 0,183,3,0,0,115,22,0,0,0,8,5,4,2,8,6, + 0,184,3,0,0,115,22,0,0,0,8,5,4,2,8,6, 8,10,8,4,8,13,8,3,8,3,8,3,8,3,8,3, 114,227,0,0,0,99,0,0,0,0,0,0,0,0,0,0, 0,0,3,0,0,0,64,0,0,0,115,80,0,0,0,101, @@ -1704,7 +1704,7 @@ 1,78,41,2,114,227,0,0,0,114,229,0,0,0,41,4, 114,104,0,0,0,114,102,0,0,0,114,37,0,0,0,114, 233,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,182,0,0,0,244,3,0,0,115,2,0,0, + 0,0,0,114,182,0,0,0,245,3,0,0,115,2,0,0, 0,0,1,122,25,95,78,97,109,101,115,112,97,99,101,76, 111,97,100,101,114,46,95,95,105,110,105,116,95,95,99,2, 0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,67, @@ -1721,21 +1721,21 @@ 112,97,99,101,41,62,41,2,114,50,0,0,0,114,109,0, 0,0,41,2,114,168,0,0,0,114,187,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,109, - 111,100,117,108,101,95,114,101,112,114,247,3,0,0,115,2, + 111,100,117,108,101,95,114,101,112,114,248,3,0,0,115,2, 0,0,0,0,7,122,28,95,78,97,109,101,115,112,97,99, 101,76,111,97,100,101,114,46,109,111,100,117,108,101,95,114, 101,112,114,99,2,0,0,0,0,0,0,0,2,0,0,0, 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, 0,41,2,78,84,114,4,0,0,0,41,2,114,104,0,0, 0,114,123,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,114,157,0,0,0,0,4,0,0,115,2, + 114,6,0,0,0,114,157,0,0,0,1,4,0,0,115,2, 0,0,0,0,1,122,27,95,78,97,109,101,115,112,97,99, 101,76,111,97,100,101,114,46,105,115,95,112,97,99,107,97, 103,101,99,2,0,0,0,0,0,0,0,2,0,0,0,1, 0,0,0,67,0,0,0,115,4,0,0,0,100,1,83,0, 41,2,78,114,32,0,0,0,114,4,0,0,0,41,2,114, 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,199,0,0,0,3,4,0, + 0,0,0,114,6,0,0,0,114,199,0,0,0,4,4,0, 0,115,2,0,0,0,0,1,122,27,95,78,97,109,101,115, 112,97,99,101,76,111,97,100,101,114,46,103,101,116,95,115, 111,117,114,99,101,99,2,0,0,0,0,0,0,0,2,0, @@ -1745,7 +1745,7 @@ 62,114,186,0,0,0,84,41,1,114,201,0,0,0,41,1, 114,202,0,0,0,41,2,114,104,0,0,0,114,123,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,184,0,0,0,6,4,0,0,115,2,0,0,0,0,1, + 114,184,0,0,0,7,4,0,0,115,2,0,0,0,0,1, 122,25,95,78,97,109,101,115,112,97,99,101,76,111,97,100, 101,114,46,103,101,116,95,99,111,100,101,99,2,0,0,0, 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, @@ -1754,14 +1754,14 @@ 99,115,32,102,111,114,32,109,111,100,117,108,101,32,99,114, 101,97,116,105,111,110,46,78,114,4,0,0,0,41,2,114, 104,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,183,0,0,0,9,4,0, + 0,0,0,114,6,0,0,0,114,183,0,0,0,10,4,0, 0,115,0,0,0,0,122,30,95,78,97,109,101,115,112,97, 99,101,76,111,97,100,101,114,46,99,114,101,97,116,101,95, 109,111,100,117,108,101,99,2,0,0,0,0,0,0,0,2, 0,0,0,1,0,0,0,67,0,0,0,115,4,0,0,0, 100,0,83,0,41,1,78,114,4,0,0,0,41,2,114,104, 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,188,0,0,0,12,4,0,0, + 0,0,114,6,0,0,0,114,188,0,0,0,13,4,0,0, 115,2,0,0,0,0,1,122,28,95,78,97,109,101,115,112, 97,99,101,76,111,97,100,101,114,46,101,120,101,99,95,109, 111,100,117,108,101,99,2,0,0,0,0,0,0,0,2,0, @@ -1779,7 +1779,7 @@ 116,104,32,123,33,114,125,41,4,114,118,0,0,0,114,133, 0,0,0,114,229,0,0,0,114,189,0,0,0,41,2,114, 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,190,0,0,0,15,4,0, + 0,0,0,114,6,0,0,0,114,190,0,0,0,16,4,0, 0,115,6,0,0,0,0,7,6,1,8,1,122,28,95,78, 97,109,101,115,112,97,99,101,76,111,97,100,101,114,46,108, 111,97,100,95,109,111,100,117,108,101,78,41,12,114,109,0, @@ -1788,7 +1788,7 @@ 114,199,0,0,0,114,184,0,0,0,114,183,0,0,0,114, 188,0,0,0,114,190,0,0,0,114,4,0,0,0,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,114,246,0, - 0,0,243,3,0,0,115,16,0,0,0,8,1,8,3,12, + 0,0,244,3,0,0,115,16,0,0,0,8,1,8,3,12, 9,8,3,8,3,8,3,8,3,8,3,114,246,0,0,0, 99,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,64,0,0,0,115,106,0,0,0,101,0,90,1,100,0, @@ -1821,7 +1821,7 @@ 114,95,99,97,99,104,101,218,6,118,97,108,117,101,115,114, 112,0,0,0,114,249,0,0,0,41,2,114,168,0,0,0, 218,6,102,105,110,100,101,114,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,33,4,0,0, + 0,0,114,6,0,0,0,114,249,0,0,0,34,4,0,0, 115,6,0,0,0,0,4,16,1,10,1,122,28,80,97,116, 104,70,105,110,100,101,114,46,105,110,118,97,108,105,100,97, 116,101,95,99,97,99,104,101,115,99,2,0,0,0,0,0, @@ -1841,7 +1841,7 @@ 0,0,114,122,0,0,0,114,103,0,0,0,41,3,114,168, 0,0,0,114,37,0,0,0,90,4,104,111,111,107,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,95, - 112,97,116,104,95,104,111,111,107,115,41,4,0,0,115,16, + 112,97,116,104,95,104,111,111,107,115,42,4,0,0,115,16, 0,0,0,0,3,18,1,12,1,12,1,2,1,8,1,14, 1,12,2,122,22,80,97,116,104,70,105,110,100,101,114,46, 95,112,97,116,104,95,104,111,111,107,115,99,2,0,0,0, @@ -1873,7 +1873,7 @@ 0,114,37,0,0,0,114,252,0,0,0,114,4,0,0,0, 114,4,0,0,0,114,6,0,0,0,218,20,95,112,97,116, 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 54,4,0,0,115,22,0,0,0,0,8,8,1,2,1,12, + 55,4,0,0,115,22,0,0,0,0,8,8,1,2,1,12, 1,14,3,6,1,2,1,14,1,14,1,10,1,16,1,122, 31,80,97,116,104,70,105,110,100,101,114,46,95,112,97,116, 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, @@ -1890,7 +1890,7 @@ 114,123,0,0,0,114,252,0,0,0,114,124,0,0,0,114, 125,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, 0,0,0,114,6,0,0,0,218,16,95,108,101,103,97,99, - 121,95,103,101,116,95,115,112,101,99,76,4,0,0,115,18, + 121,95,103,101,116,95,115,112,101,99,77,4,0,0,115,18, 0,0,0,0,4,10,1,16,2,10,1,4,1,8,1,12, 1,12,1,6,1,122,27,80,97,116,104,70,105,110,100,101, 114,46,95,108,101,103,97,99,121,95,103,101,116,95,115,112, @@ -1922,7 +1922,7 @@ 90,5,101,110,116,114,121,114,252,0,0,0,114,162,0,0, 0,114,125,0,0,0,114,4,0,0,0,114,4,0,0,0, 114,6,0,0,0,218,9,95,103,101,116,95,115,112,101,99, - 91,4,0,0,115,40,0,0,0,0,5,4,1,10,1,14, + 92,4,0,0,115,40,0,0,0,0,5,4,1,10,1,14, 1,2,1,10,1,8,1,10,1,14,2,12,1,8,1,2, 1,10,1,4,1,6,1,8,1,8,5,14,2,12,1,6, 1,122,20,80,97,116,104,70,105,110,100,101,114,46,95,103, @@ -1949,7 +1949,7 @@ 0,114,156,0,0,0,114,227,0,0,0,41,6,114,168,0, 0,0,114,123,0,0,0,114,37,0,0,0,114,177,0,0, 0,114,162,0,0,0,114,3,1,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,123, + 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,124, 4,0,0,115,26,0,0,0,0,6,8,1,6,1,14,1, 8,1,6,1,10,1,6,1,4,3,6,1,16,1,6,2, 6,2,122,20,80,97,116,104,70,105,110,100,101,114,46,102, @@ -1971,7 +1971,7 @@ 2,114,178,0,0,0,114,124,0,0,0,41,4,114,168,0, 0,0,114,123,0,0,0,114,37,0,0,0,114,162,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,179,0,0,0,147,4,0,0,115,8,0,0,0,0,8, + 114,179,0,0,0,148,4,0,0,115,8,0,0,0,0,8, 12,1,8,1,4,1,122,22,80,97,116,104,70,105,110,100, 101,114,46,102,105,110,100,95,109,111,100,117,108,101,41,1, 78,41,2,78,78,41,1,78,41,12,114,109,0,0,0,114, @@ -1979,7 +1979,7 @@ 0,0,0,114,249,0,0,0,114,254,0,0,0,114,0,1, 0,0,114,1,1,0,0,114,4,1,0,0,114,178,0,0, 0,114,179,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,248,0,0,0,29, + 114,4,0,0,0,114,6,0,0,0,114,248,0,0,0,30, 4,0,0,115,22,0,0,0,8,2,4,2,12,8,12,13, 12,22,12,15,2,1,12,31,2,1,12,23,2,1,114,248, 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0, @@ -2023,7 +2023,7 @@ 14,125,1,124,1,136,0,102,2,86,0,1,0,113,2,100, 0,83,0,41,1,78,114,4,0,0,0,41,2,114,24,0, 0,0,114,222,0,0,0,41,1,114,124,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,224,0,0,0,176,4,0, + 0,0,0,114,6,0,0,0,114,224,0,0,0,177,4,0, 0,115,2,0,0,0,4,0,122,38,70,105,108,101,70,105, 110,100,101,114,46,95,95,105,110,105,116,95,95,46,60,108, 111,99,97,108,115,62,46,60,103,101,110,101,120,112,114,62, @@ -2036,7 +2036,7 @@ 0,114,37,0,0,0,218,14,108,111,97,100,101,114,95,100, 101,116,97,105,108,115,90,7,108,111,97,100,101,114,115,114, 164,0,0,0,114,4,0,0,0,41,1,114,124,0,0,0, - 114,6,0,0,0,114,182,0,0,0,170,4,0,0,115,16, + 114,6,0,0,0,114,182,0,0,0,171,4,0,0,115,16, 0,0,0,0,4,4,1,14,1,28,1,6,2,10,1,6, 1,8,1,122,19,70,105,108,101,70,105,110,100,101,114,46, 95,95,105,110,105,116,95,95,99,1,0,0,0,0,0,0, @@ -2046,7 +2046,7 @@ 105,114,101,99,116,111,114,121,32,109,116,105,109,101,46,114, 31,0,0,0,78,114,91,0,0,0,41,1,114,7,1,0, 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,184,4,0,0, + 0,0,114,6,0,0,0,114,249,0,0,0,185,4,0,0, 115,2,0,0,0,0,2,122,28,70,105,108,101,70,105,110, 100,101,114,46,105,110,118,97,108,105,100,97,116,101,95,99, 97,99,104,101,115,99,2,0,0,0,0,0,0,0,3,0, @@ -2069,7 +2069,7 @@ 32,32,78,41,3,114,178,0,0,0,114,124,0,0,0,114, 154,0,0,0,41,3,114,104,0,0,0,114,123,0,0,0, 114,162,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,121,0,0,0,190,4,0,0,115,8,0, + 6,0,0,0,114,121,0,0,0,191,4,0,0,115,8,0, 0,0,0,7,10,1,8,1,8,1,122,22,70,105,108,101, 70,105,110,100,101,114,46,102,105,110,100,95,108,111,97,100, 101,114,99,6,0,0,0,0,0,0,0,7,0,0,0,6, @@ -2080,7 +2080,7 @@ 0,0,0,114,163,0,0,0,114,123,0,0,0,114,37,0, 0,0,90,4,115,109,115,108,114,177,0,0,0,114,124,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,4,1,0,0,202,4,0,0,115,6,0,0,0,0, + 0,114,4,1,0,0,203,4,0,0,115,6,0,0,0,0, 1,10,1,8,1,122,20,70,105,108,101,70,105,110,100,101, 114,46,95,103,101,116,95,115,112,101,99,78,99,3,0,0, 0,0,0,0,0,14,0,0,0,15,0,0,0,67,0,0, @@ -2134,7 +2134,7 @@ 116,104,114,222,0,0,0,114,163,0,0,0,90,13,105,110, 105,116,95,102,105,108,101,110,97,109,101,90,9,102,117,108, 108,95,112,97,116,104,114,162,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,207, + 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,208, 4,0,0,115,70,0,0,0,0,5,4,1,14,1,2,1, 24,1,14,1,10,1,10,1,8,1,6,2,6,1,6,1, 10,2,6,1,4,2,8,1,12,1,16,1,8,1,10,1, @@ -2166,7 +2166,7 @@ 0,146,2,113,4,83,0,114,4,0,0,0,41,1,114,92, 0,0,0,41,2,114,24,0,0,0,90,2,102,110,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,250,9,60, - 115,101,116,99,111,109,112,62,28,5,0,0,115,2,0,0, + 115,101,116,99,111,109,112,62,29,5,0,0,115,2,0,0, 0,6,0,122,41,70,105,108,101,70,105,110,100,101,114,46, 95,102,105,108,108,95,99,97,99,104,101,46,60,108,111,99, 97,108,115,62,46,60,115,101,116,99,111,109,112,62,78,41, @@ -2183,7 +2183,7 @@ 111,110,116,101,110,116,115,114,244,0,0,0,114,102,0,0, 0,114,234,0,0,0,114,222,0,0,0,90,8,110,101,119, 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,12,1,0,0,255,4,0,0,115,34,0, + 6,0,0,0,114,12,1,0,0,0,5,0,0,115,34,0, 0,0,0,2,6,1,2,1,22,1,20,3,10,3,12,1, 12,7,6,1,10,1,16,1,4,1,18,2,4,1,14,1, 6,1,12,1,122,22,70,105,108,101,70,105,110,100,101,114, @@ -2211,7 +2211,7 @@ 32,32,32,99,1,0,0,0,0,0,0,0,1,0,0,0, 4,0,0,0,19,0,0,0,115,34,0,0,0,116,0,124, 0,131,1,115,20,116,1,100,1,124,0,100,2,141,2,130, - 1,136,0,124,0,102,1,136,1,152,2,142,0,83,0,41, + 1,136,0,124,0,102,1,136,1,158,2,142,0,83,0,41, 3,122,45,80,97,116,104,32,104,111,111,107,32,102,111,114, 32,105,109,112,111,114,116,108,105,98,46,109,97,99,104,105, 110,101,114,121,46,70,105,108,101,70,105,110,100,101,114,46, @@ -2221,7 +2221,7 @@ 0,0,0,41,1,114,37,0,0,0,41,2,114,168,0,0, 0,114,11,1,0,0,114,4,0,0,0,114,6,0,0,0, 218,24,112,97,116,104,95,104,111,111,107,95,102,111,114,95, - 70,105,108,101,70,105,110,100,101,114,40,5,0,0,115,6, + 70,105,108,101,70,105,110,100,101,114,41,5,0,0,115,6, 0,0,0,0,2,8,1,12,1,122,54,70,105,108,101,70, 105,110,100,101,114,46,112,97,116,104,95,104,111,111,107,46, 60,108,111,99,97,108,115,62,46,112,97,116,104,95,104,111, @@ -2229,7 +2229,7 @@ 114,114,4,0,0,0,41,3,114,168,0,0,0,114,11,1, 0,0,114,17,1,0,0,114,4,0,0,0,41,2,114,168, 0,0,0,114,11,1,0,0,114,6,0,0,0,218,9,112, - 97,116,104,95,104,111,111,107,30,5,0,0,115,4,0,0, + 97,116,104,95,104,111,111,107,31,5,0,0,115,4,0,0, 0,0,10,14,6,122,20,70,105,108,101,70,105,110,100,101, 114,46,112,97,116,104,95,104,111,111,107,99,1,0,0,0, 0,0,0,0,1,0,0,0,2,0,0,0,67,0,0,0, @@ -2237,7 +2237,7 @@ 0,41,2,78,122,16,70,105,108,101,70,105,110,100,101,114, 40,123,33,114,125,41,41,2,114,50,0,0,0,114,37,0, 0,0,41,1,114,104,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,243,0,0,0,48,5,0, + 0,0,0,114,6,0,0,0,114,243,0,0,0,49,5,0, 0,115,2,0,0,0,0,1,122,19,70,105,108,101,70,105, 110,100,101,114,46,95,95,114,101,112,114,95,95,41,1,78, 41,15,114,109,0,0,0,114,108,0,0,0,114,110,0,0, @@ -2246,7 +2246,7 @@ 4,1,0,0,114,178,0,0,0,114,12,1,0,0,114,180, 0,0,0,114,18,1,0,0,114,243,0,0,0,114,4,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,5,1,0,0,161,4,0,0,115,20,0,0,0,8, + 0,114,5,1,0,0,162,4,0,0,115,20,0,0,0,8, 7,4,2,8,14,8,4,4,2,8,12,8,5,10,48,8, 31,12,18,114,5,1,0,0,99,4,0,0,0,0,0,0, 0,6,0,0,0,11,0,0,0,67,0,0,0,115,146,0, @@ -2269,7 +2269,7 @@ 104,110,97,109,101,90,9,99,112,97,116,104,110,97,109,101, 114,124,0,0,0,114,162,0,0,0,114,4,0,0,0,114, 4,0,0,0,114,6,0,0,0,218,14,95,102,105,120,95, - 117,112,95,109,111,100,117,108,101,54,5,0,0,115,34,0, + 117,112,95,109,111,100,117,108,101,55,5,0,0,115,34,0, 0,0,0,2,10,1,10,1,4,1,4,1,8,1,8,1, 12,2,10,1,4,1,14,1,2,1,8,1,8,1,8,1, 12,1,14,2,114,23,1,0,0,99,0,0,0,0,0,0, @@ -2289,7 +2289,7 @@ 41,3,90,10,101,120,116,101,110,115,105,111,110,115,90,6, 115,111,117,114,99,101,90,8,98,121,116,101,99,111,100,101, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 159,0,0,0,77,5,0,0,115,8,0,0,0,0,5,12, + 159,0,0,0,78,5,0,0,115,8,0,0,0,0,5,12, 1,8,1,8,1,114,159,0,0,0,99,1,0,0,0,0, 0,0,0,12,0,0,0,12,0,0,0,67,0,0,0,115, 188,1,0,0,124,0,97,0,116,0,106,1,97,1,116,0, @@ -2341,7 +2341,7 @@ 1,100,0,107,2,86,0,1,0,113,2,100,1,83,0,41, 2,114,31,0,0,0,78,41,1,114,33,0,0,0,41,2, 114,24,0,0,0,114,81,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,224,0,0,0,113,5, + 4,0,0,0,114,6,0,0,0,114,224,0,0,0,114,5, 0,0,115,2,0,0,0,4,0,122,25,95,115,101,116,117, 112,46,60,108,111,99,97,108,115,62,46,60,103,101,110,101, 120,112,114,62,114,62,0,0,0,122,30,105,109,112,111,114, @@ -2371,7 +2371,7 @@ 14,119,101,97,107,114,101,102,95,109,111,100,117,108,101,90, 13,119,105,110,114,101,103,95,109,111,100,117,108,101,114,4, 0,0,0,114,4,0,0,0,114,6,0,0,0,218,6,95, - 115,101,116,117,112,88,5,0,0,115,82,0,0,0,0,8, + 115,101,116,117,112,89,5,0,0,115,82,0,0,0,0,8, 4,1,6,1,6,3,10,1,10,1,10,1,12,2,10,1, 16,3,22,1,14,2,22,1,8,1,10,1,10,1,4,2, 2,1,10,1,6,1,14,1,12,2,8,1,12,1,12,1, @@ -2394,7 +2394,7 @@ 0,0,0,41,2,114,31,1,0,0,90,17,115,117,112,112, 111,114,116,101,100,95,108,111,97,100,101,114,115,114,4,0, 0,0,114,4,0,0,0,114,6,0,0,0,218,8,95,105, - 110,115,116,97,108,108,156,5,0,0,115,12,0,0,0,0, + 110,115,116,97,108,108,157,5,0,0,115,12,0,0,0,0, 2,8,1,6,1,20,1,10,1,12,1,114,34,1,0,0, 41,1,114,0,0,0,0,41,2,114,1,0,0,0,114,2, 0,0,0,41,1,114,49,0,0,0,41,1,78,41,3,78, @@ -2428,7 +2428,7 @@ 0,114,6,0,0,0,218,8,60,109,111,100,117,108,101,62, 8,0,0,0,115,108,0,0,0,4,16,4,1,4,1,2, 1,6,3,8,17,8,5,8,5,8,6,8,12,8,10,8, - 9,8,5,8,7,10,22,10,121,16,1,12,2,4,1,4, + 9,8,5,8,7,10,22,10,122,16,1,12,2,4,1,4, 2,6,2,6,2,8,2,16,45,8,34,8,19,8,12,8, 12,8,28,8,17,10,55,10,12,10,10,8,14,6,3,4, 1,14,67,14,64,14,29,16,110,14,41,18,45,18,16,4, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -157,7 +157,7 @@ &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&_unknown_opcode, + &&TARGET_BUILD_TUPLE_UNPACK_WITH_CALL, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:12:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 08:12:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3MzU4?= =?utf-8?q?=3A_Backported_tests=2E?= Message-ID: <20161002081226.20033.30562.0F55B60B@psf.io> https://hg.python.org/cpython/rev/ec84d815e90f changeset: 104235:ec84d815e90f branch: 3.5 parent: 104229:40d7ce58ebd0 user: Serhiy Storchaka date: Sun Oct 02 11:10:18 2016 +0300 summary: Issue #27358: Backported tests. files: Lib/test/test_extcall.py | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -254,6 +254,21 @@ ... TypeError: h() argument after ** must be a mapping, not function + >>> h(**[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + + >>> h(a=1, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(a=1, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + >>> dir(**h) Traceback (most recent call last): ... -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:13:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 08:13:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161002081227.79425.31395.34787F23@psf.io> https://hg.python.org/cpython/rev/6f299f7d6643 changeset: 104238:6f299f7d6643 parent: 104234:489ad68b35c0 parent: 104237:872019fd3147 user: Serhiy Storchaka date: Sun Oct 02 11:12:03 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:13:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 08:13:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Null_merge?= Message-ID: <20161002081226.21280.15640.F4A78CA4@psf.io> https://hg.python.org/cpython/rev/872019fd3147 changeset: 104237:872019fd3147 branch: 3.6 parent: 104233:148172f75d43 parent: 104235:ec84d815e90f user: Serhiy Storchaka date: Sun Oct 02 11:11:46 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:13:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 08:13:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI3MzU4?= =?utf-8?q?=3A_Backported_tests=2E?= Message-ID: <20161002081226.95094.70539.9A8F809D@psf.io> https://hg.python.org/cpython/rev/29a658d47ae8 changeset: 104236:29a658d47ae8 branch: 2.7 parent: 104230:a8168a52a56f user: Serhiy Storchaka date: Sun Oct 02 11:10:18 2016 +0300 summary: Issue #27358: Backported tests. files: Lib/test/test_extcall.py | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -201,6 +201,21 @@ ... TypeError: h() argument after ** must be a mapping, not function + >>> h(**[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + + >>> h(a=1, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(a=1, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + >>> dir(**h) Traceback (most recent call last): ... -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:13:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 08:13:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327358=3A_Optimized_merging_var-keyword_argument?= =?utf-8?q?s_and_improved_error?= Message-ID: <20161002081226.75862.10930.0C32CE3A@psf.io> https://hg.python.org/cpython/rev/489ad68b35c0 changeset: 104234:489ad68b35c0 parent: 104232:818e5416ab39 parent: 104233:148172f75d43 user: Serhiy Storchaka date: Sun Oct 02 11:07:29 2016 +0300 summary: Issue #27358: Optimized merging var-keyword arguments and improved error message when pass a non-mapping as a var-keyword argument. files: Include/dictobject.h | 6 + Lib/test/test_extcall.py | 25 ++++++ Misc/NEWS | 3 + Objects/dictobject.c | 45 +++++++++-- Python/ceval.c | 102 ++++++++++++++------------ 5 files changed, 126 insertions(+), 55 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -132,6 +132,12 @@ int override); #ifndef Py_LIMITED_API +/* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0, + the first occurrence of a key wins, if override is 1, the last occurrence + of a key wins, if override is 2, a KeyError with conflicting key as + argument is raised. +*/ +PyAPI_FUNC(int) _PyDict_MergeEx(PyObject *mp, PyObject *other, int override); PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); #endif diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -259,6 +259,31 @@ ... TypeError: h() argument after ** must be a mapping, not function + >>> h(**[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + + >>> h(a=1, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(a=1, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + + >>> h(**{'a': 1}, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(**{'a': 1}, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + >>> dir(**h) Traceback (most recent call last): ... diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,9 @@ Library ------- +- Issue #27358: Optimized merging var-keyword arguments and improved error + message when pass a non-mapping as a var-keyword argument. + - Issue #28257: Improved error message when pass a non-iterable as a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2380,18 +2380,14 @@ } int -PyDict_Update(PyObject *a, PyObject *b) -{ - return PyDict_Merge(a, b, 1); -} - -int -PyDict_Merge(PyObject *a, PyObject *b, int override) +dict_merge(PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; Py_ssize_t i, n; PyDictKeyEntry *entry, *ep0; + assert(0 <= override && override <= 2); + /* We accept for the argument either a concrete dictionary object, * or an abstract "mapping" object. For the former, we can do * things quite efficiently. For the latter, we only require that @@ -2436,8 +2432,14 @@ int err = 0; Py_INCREF(key); Py_INCREF(value); - if (override || PyDict_GetItem(a, key) == NULL) + if (override == 1 || _PyDict_GetItem_KnownHash(a, key, hash) == NULL) err = insertdict(mp, key, hash, value); + else if (override != 0) { + _PyErr_SetKeyError(key); + Py_DECREF(value); + Py_DECREF(key); + return -1; + } Py_DECREF(value); Py_DECREF(key); if (err != 0) @@ -2472,7 +2474,13 @@ return -1; for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { - if (!override && PyDict_GetItem(a, key) != NULL) { + if (override != 1 && PyDict_GetItem(a, key) != NULL) { + if (override != 0) { + _PyErr_SetKeyError(key); + Py_DECREF(key); + Py_DECREF(iter); + return -1; + } Py_DECREF(key); continue; } @@ -2499,6 +2507,25 @@ return 0; } +int +PyDict_Update(PyObject *a, PyObject *b) +{ + return dict_merge(a, b, 1); +} + +int +PyDict_Merge(PyObject *a, PyObject *b, int override) +{ + /* XXX Deprecate override not in (0, 1). */ + return dict_merge(a, b, override != 0); +} + +int +_PyDict_MergeEx(PyObject *a, PyObject *b, int override) +{ + return dict_merge(a, b, override); +} + static PyObject * dict_copy(PyDictObject *mp) { diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2710,9 +2710,7 @@ DISPATCH(); } - TARGET(BUILD_MAP_UNPACK_WITH_CALL) TARGET(BUILD_MAP_UNPACK) { - int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL; Py_ssize_t i; PyObject *sum = PyDict_New(); if (sum == NULL) @@ -2720,53 +2718,10 @@ for (i = oparg; i > 0; i--) { PyObject *arg = PEEK(i); - if (with_call && PyDict_Size(sum)) { - PyObject *intersection = _PyDictView_Intersect(sum, arg); - - if (intersection == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyObject *func = PEEK(2 + oparg); - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after ** " - "must be a mapping, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - arg->ob_type->tp_name); - } - Py_DECREF(sum); - goto error; - } - - if (PySet_GET_SIZE(intersection)) { - Py_ssize_t idx = 0; - PyObject *key; - PyObject *func = PEEK(2 + oparg); - Py_hash_t hash; - _PySet_NextEntry(intersection, &idx, &key, &hash); - if (!PyUnicode_Check(key)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s keywords must be strings", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func)); - } else { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s got multiple " - "values for keyword argument '%U'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - key); - } - Py_DECREF(intersection); - Py_DECREF(sum); - goto error; - } - Py_DECREF(intersection); - } - if (PyDict_Update(sum, arg) < 0) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping", + "'%.200s' object is not a mapping1", arg->ob_type->tp_name); } Py_DECREF(sum); @@ -2780,6 +2735,61 @@ DISPATCH(); } + TARGET(BUILD_MAP_UNPACK_WITH_CALL) { + Py_ssize_t i; + PyObject *sum = PyDict_New(); + if (sum == NULL) + goto error; + + for (i = oparg; i > 0; i--) { + PyObject *arg = PEEK(i); + if (_PyDict_MergeEx(sum, arg, 2) < 0) { + PyObject *func = PEEK(2 + oparg); + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after ** " + "must be a mapping, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + arg->ob_type->tp_name); + } + else if (PyErr_ExceptionMatches(PyExc_KeyError)) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) { + PyObject *key = PyTuple_GET_ITEM(val, 0); + if (!PyUnicode_Check(key)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s keywords must be strings", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func)); + } else { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s got multiple " + "values for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + } + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + } + else { + PyErr_Restore(exc, val, tb); + } + } + Py_DECREF(sum); + goto error; + } + } + + while (oparg--) + Py_DECREF(POP()); + PUSH(sum); + DISPATCH(); + } + TARGET(MAP_ADD) { PyObject *key = TOP(); PyObject *value = SECOND(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:13:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 08:13:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI3MzU4?= =?utf-8?q?=3A_Optimized_merging_var-keyword_arguments_and_improved_error?= Message-ID: <20161002081225.85724.40430.BF71DB04@psf.io> https://hg.python.org/cpython/rev/148172f75d43 changeset: 104233:148172f75d43 branch: 3.6 parent: 104231:d619246e5eb7 user: Serhiy Storchaka date: Sun Oct 02 11:06:43 2016 +0300 summary: Issue #27358: Optimized merging var-keyword arguments and improved error message when pass a non-mapping as a var-keyword argument. files: Include/dictobject.h | 6 + Lib/test/test_extcall.py | 25 ++++++ Misc/NEWS | 3 + Objects/dictobject.c | 45 +++++++++-- Python/ceval.c | 102 ++++++++++++++------------ 5 files changed, 126 insertions(+), 55 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -132,6 +132,12 @@ int override); #ifndef Py_LIMITED_API +/* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0, + the first occurrence of a key wins, if override is 1, the last occurrence + of a key wins, if override is 2, a KeyError with conflicting key as + argument is raised. +*/ +PyAPI_FUNC(int) _PyDict_MergeEx(PyObject *mp, PyObject *other, int override); PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); #endif diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -259,6 +259,31 @@ ... TypeError: h() argument after ** must be a mapping, not function + >>> h(**[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + + >>> h(a=1, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(a=1, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + + >>> h(**{'a': 1}, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(**{'a': 1}, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + >>> dir(**h) Traceback (most recent call last): ... diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,9 @@ Library ------- +- Issue #27358: Optimized merging var-keyword arguments and improved error + message when pass a non-mapping as a var-keyword argument. + - Issue #28257: Improved error message when pass a non-iterable as a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2380,18 +2380,14 @@ } int -PyDict_Update(PyObject *a, PyObject *b) -{ - return PyDict_Merge(a, b, 1); -} - -int -PyDict_Merge(PyObject *a, PyObject *b, int override) +dict_merge(PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; Py_ssize_t i, n; PyDictKeyEntry *entry, *ep0; + assert(0 <= override && override <= 2); + /* We accept for the argument either a concrete dictionary object, * or an abstract "mapping" object. For the former, we can do * things quite efficiently. For the latter, we only require that @@ -2436,8 +2432,14 @@ int err = 0; Py_INCREF(key); Py_INCREF(value); - if (override || PyDict_GetItem(a, key) == NULL) + if (override == 1 || _PyDict_GetItem_KnownHash(a, key, hash) == NULL) err = insertdict(mp, key, hash, value); + else if (override != 0) { + _PyErr_SetKeyError(key); + Py_DECREF(value); + Py_DECREF(key); + return -1; + } Py_DECREF(value); Py_DECREF(key); if (err != 0) @@ -2472,7 +2474,13 @@ return -1; for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { - if (!override && PyDict_GetItem(a, key) != NULL) { + if (override != 1 && PyDict_GetItem(a, key) != NULL) { + if (override != 0) { + _PyErr_SetKeyError(key); + Py_DECREF(key); + Py_DECREF(iter); + return -1; + } Py_DECREF(key); continue; } @@ -2499,6 +2507,25 @@ return 0; } +int +PyDict_Update(PyObject *a, PyObject *b) +{ + return dict_merge(a, b, 1); +} + +int +PyDict_Merge(PyObject *a, PyObject *b, int override) +{ + /* XXX Deprecate override not in (0, 1). */ + return dict_merge(a, b, override != 0); +} + +int +_PyDict_MergeEx(PyObject *a, PyObject *b, int override) +{ + return dict_merge(a, b, override); +} + static PyObject * dict_copy(PyDictObject *mp) { diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2710,9 +2710,7 @@ DISPATCH(); } - TARGET(BUILD_MAP_UNPACK_WITH_CALL) TARGET(BUILD_MAP_UNPACK) { - int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL; Py_ssize_t i; PyObject *sum = PyDict_New(); if (sum == NULL) @@ -2720,53 +2718,10 @@ for (i = oparg; i > 0; i--) { PyObject *arg = PEEK(i); - if (with_call && PyDict_Size(sum)) { - PyObject *intersection = _PyDictView_Intersect(sum, arg); - - if (intersection == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyObject *func = PEEK(2 + oparg); - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after ** " - "must be a mapping, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - arg->ob_type->tp_name); - } - Py_DECREF(sum); - goto error; - } - - if (PySet_GET_SIZE(intersection)) { - Py_ssize_t idx = 0; - PyObject *key; - PyObject *func = PEEK(2 + oparg); - Py_hash_t hash; - _PySet_NextEntry(intersection, &idx, &key, &hash); - if (!PyUnicode_Check(key)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s keywords must be strings", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func)); - } else { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s got multiple " - "values for keyword argument '%U'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - key); - } - Py_DECREF(intersection); - Py_DECREF(sum); - goto error; - } - Py_DECREF(intersection); - } - if (PyDict_Update(sum, arg) < 0) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping", + "'%.200s' object is not a mapping1", arg->ob_type->tp_name); } Py_DECREF(sum); @@ -2780,6 +2735,61 @@ DISPATCH(); } + TARGET(BUILD_MAP_UNPACK_WITH_CALL) { + Py_ssize_t i; + PyObject *sum = PyDict_New(); + if (sum == NULL) + goto error; + + for (i = oparg; i > 0; i--) { + PyObject *arg = PEEK(i); + if (_PyDict_MergeEx(sum, arg, 2) < 0) { + PyObject *func = PEEK(2 + oparg); + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after ** " + "must be a mapping, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + arg->ob_type->tp_name); + } + else if (PyErr_ExceptionMatches(PyExc_KeyError)) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) { + PyObject *key = PyTuple_GET_ITEM(val, 0); + if (!PyUnicode_Check(key)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s keywords must be strings", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func)); + } else { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s got multiple " + "values for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + } + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + } + else { + PyErr_Restore(exc, val, tb); + } + } + Py_DECREF(sum); + goto error; + } + } + + while (oparg--) + Py_DECREF(POP()); + PUSH(sum); + DISPATCH(); + } + TARGET(MAP_ADD) { PyObject *key = TOP(); PyObject *value = SECOND(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:38:16 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 08:38:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2320254=3A_Merge_from_3=2E5?= Message-ID: <20161002083815.1685.62854.EF8382A7@psf.io> https://hg.python.org/cpython/rev/ac9734540eb7 changeset: 104240:ac9734540eb7 branch: 3.6 parent: 104237:872019fd3147 parent: 104239:6406322f4749 user: Berker Peksag date: Sun Oct 02 11:40:10 2016 +0300 summary: Issue #20254: Merge from 3.5 files: Lib/test/test_socket.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 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 @@ -4668,9 +4668,10 @@ SocketConnectedTest.__init__(self, methodName=methodName) def testRecvIntoArray(self): - buf = bytearray(1024) + buf = array.array("B", [0] * len(MSG)) nbytes = self.cli_conn.recv_into(buf) self.assertEqual(nbytes, len(MSG)) + buf = buf.tobytes() msg = buf[:len(MSG)] self.assertEqual(msg, MSG) @@ -4697,9 +4698,10 @@ _testRecvIntoMemoryview = _testRecvIntoArray def testRecvFromIntoArray(self): - buf = bytearray(1024) + buf = array.array("B", [0] * len(MSG)) nbytes, addr = self.cli_conn.recvfrom_into(buf) self.assertEqual(nbytes, len(MSG)) + buf = buf.tobytes() msg = buf[:len(MSG)] self.assertEqual(msg, MSG) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:38:16 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 08:38:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIwMjU0?= =?utf-8?q?=3A_Fix_duplicate_tests_in_test=5Fsocket?= Message-ID: <20161002083815.5570.26536.F5DA5B98@psf.io> https://hg.python.org/cpython/rev/6406322f4749 changeset: 104239:6406322f4749 branch: 3.5 parent: 104235:ec84d815e90f user: Berker Peksag date: Sun Oct 02 11:39:41 2016 +0300 summary: Issue #20254: Fix duplicate tests in test_socket Patch by Vajrasky Kok. files: Lib/test/test_socket.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 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 @@ -4629,9 +4629,10 @@ SocketConnectedTest.__init__(self, methodName=methodName) def testRecvIntoArray(self): - buf = bytearray(1024) + buf = array.array("B", [0] * len(MSG)) nbytes = self.cli_conn.recv_into(buf) self.assertEqual(nbytes, len(MSG)) + buf = buf.tobytes() msg = buf[:len(MSG)] self.assertEqual(msg, MSG) @@ -4658,9 +4659,10 @@ _testRecvIntoMemoryview = _testRecvIntoArray def testRecvFromIntoArray(self): - buf = bytearray(1024) + buf = array.array("B", [0] * len(MSG)) nbytes, addr = self.cli_conn.recvfrom_into(buf) self.assertEqual(nbytes, len(MSG)) + buf = buf.tobytes() msg = buf[:len(MSG)] self.assertEqual(msg, MSG) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 04:38:16 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 08:38:16 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320254=3A_Merge_from_3=2E6?= Message-ID: <20161002083816.82140.78899.BC2F936A@psf.io> https://hg.python.org/cpython/rev/7dab3c6ac42f changeset: 104241:7dab3c6ac42f parent: 104238:6f299f7d6643 parent: 104240:ac9734540eb7 user: Berker Peksag date: Sun Oct 02 11:40:30 2016 +0300 summary: Issue #20254: Merge from 3.6 files: Lib/test/test_socket.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 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 @@ -4668,9 +4668,10 @@ SocketConnectedTest.__init__(self, methodName=methodName) def testRecvIntoArray(self): - buf = bytearray(1024) + buf = array.array("B", [0] * len(MSG)) nbytes = self.cli_conn.recv_into(buf) self.assertEqual(nbytes, len(MSG)) + buf = buf.tobytes() msg = buf[:len(MSG)] self.assertEqual(msg, MSG) @@ -4697,9 +4698,10 @@ _testRecvIntoMemoryview = _testRecvIntoArray def testRecvFromIntoArray(self): - buf = bytearray(1024) + buf = array.array("B", [0] * len(MSG)) nbytes, addr = self.cli_conn.recvfrom_into(buf) self.assertEqual(nbytes, len(MSG)) + buf = buf.tobytes() msg = buf[:len(MSG)] self.assertEqual(msg, MSG) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 05:35:13 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 09:35:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328332=3A_Deprecat?= =?utf-8?q?ed_silent_truncations_in_socket=2Ehtons_and_socket=2Entohs=2E?= Message-ID: <20161002093513.1685.78460.33582414@psf.io> https://hg.python.org/cpython/rev/3da460ca854b changeset: 104242:3da460ca854b user: Serhiy Storchaka date: Sun Oct 02 12:34:40 2016 +0300 summary: Issue #28332: Deprecated silent truncations in socket.htons and socket.ntohs. Original patch by Oren Milman. files: Doc/library/socket.rst | 12 +++++ Lib/test/test_socket.py | 26 ++++++++--- Misc/NEWS | 3 + Modules/socketmodule.c | 60 +++++++++++++++++++++------- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -664,6 +664,12 @@ where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation. + .. deprecated:: 3.7 + In case *x* does not fit in 16-bit unsigned integer, but does fit in a + positive C int, it is silently truncated to 16-bit unsigned integer. + This silent truncation feature is deprecated, and will raise an + exception in future versions of Python. + .. function:: htonl(x) @@ -678,6 +684,12 @@ where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation. + .. deprecated:: 3.7 + In case *x* does not fit in 16-bit unsigned integer, but does fit in a + positive C int, it is silently truncated to 16-bit unsigned integer. + This silent truncation feature is deprecated, and will raise an + exception in future versions of Python. + .. function:: inet_aton(ip_string) 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 @@ -888,18 +888,28 @@ self.assertRaises(OverflowError, func, 1<<34) def testNtoHErrors(self): - good_values = [ 1, 2, 3, 1, 2, 3 ] - bad_values = [ -1, -2, -3, -1, -2, -3 ] - for k in good_values: + import _testcapi + s_good_values = [0, 1, 2, 0xffff] + l_good_values = s_good_values + [0xffffffff] + l_bad_values = [-1, -2, 1<<32, 1<<1000] + s_bad_values = l_bad_values + [_testcapi.INT_MIN - 1, + _testcapi.INT_MAX + 1] + s_deprecated_values = [1<<16, _testcapi.INT_MAX] + for k in s_good_values: + socket.ntohs(k) + socket.htons(k) + for k in l_good_values: socket.ntohl(k) - socket.ntohs(k) socket.htonl(k) - socket.htons(k) - for k in bad_values: + for k in s_bad_values: + self.assertRaises(OverflowError, socket.ntohs, k) + self.assertRaises(OverflowError, socket.htons, k) + for k in l_bad_values: self.assertRaises(OverflowError, socket.ntohl, k) - self.assertRaises(OverflowError, socket.ntohs, k) self.assertRaises(OverflowError, socket.htonl, k) - self.assertRaises(OverflowError, socket.htons, k) + for k in s_deprecated_values: + self.assertWarns(DeprecationWarning, socket.ntohs, k) + self.assertWarns(DeprecationWarning, socket.htons, k) def testGetServBy(self): eq = self.assertEqual diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,9 @@ Library ------- +- Issue #28332: Deprecated silent truncations in socket.htons and socket.ntohs. + Original patch by Oren Milman. + - Issue #27358: Optimized merging var-keyword arguments and improved error message when pass a non-mapping as a var-keyword argument. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5498,24 +5498,38 @@ static PyObject * socket_ntohs(PyObject *self, PyObject *args) { - int x1, x2; - - if (!PyArg_ParseTuple(args, "i:ntohs", &x1)) { + int x; + + if (!PyArg_ParseTuple(args, "i:ntohs", &x)) { return NULL; } - if (x1 < 0) { + if (x < 0) { PyErr_SetString(PyExc_OverflowError, - "can't convert negative number to unsigned long"); + "ntohs: can't convert negative Python int to C " + "16-bit unsigned integer"); return NULL; } - x2 = (unsigned int)ntohs((unsigned short)x1); - return PyLong_FromLong(x2); + if (x > 0xffff) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "ntohs: Python int too large to convert to C " + "16-bit unsigned integer (The silent truncation " + "is deprecated)", + 1)) { + return NULL; + } + } + return PyLong_FromUnsignedLong(ntohs((unsigned short)x)); } PyDoc_STRVAR(ntohs_doc, "ntohs(integer) -> integer\n\ \n\ -Convert a 16-bit integer from network to host byte order."); +Convert a 16-bit unsigned integer from network to host byte order.\n\ +Note that in case the received integer does not fit in 16-bit unsigned\n\ +integer, but does fit in a positive C int, it is silently truncated to\n\ +16-bit unsigned integer.\n\ +However, this silent truncation feature is deprecated, and will raise an \n\ +exception in future versions of Python."); static PyObject * @@ -5555,24 +5569,38 @@ static PyObject * socket_htons(PyObject *self, PyObject *args) { - int x1, x2; - - if (!PyArg_ParseTuple(args, "i:htons", &x1)) { + int x; + + if (!PyArg_ParseTuple(args, "i:htons", &x)) { return NULL; } - if (x1 < 0) { + if (x < 0) { PyErr_SetString(PyExc_OverflowError, - "can't convert negative number to unsigned long"); + "htons: can't convert negative Python int to C " + "16-bit unsigned integer"); return NULL; } - x2 = (unsigned int)htons((unsigned short)x1); - return PyLong_FromLong(x2); + if (x > 0xffff) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "htons: Python int too large to convert to C " + "16-bit unsigned integer (The silent truncation " + "is deprecated)", + 1)) { + return NULL; + } + } + return PyLong_FromUnsignedLong(htons((unsigned short)x)); } PyDoc_STRVAR(htons_doc, "htons(integer) -> integer\n\ \n\ -Convert a 16-bit integer from host to network byte order."); +Convert a 16-bit unsigned integer from host to network byte order.\n\ +Note that in case the received integer does not fit in 16-bit unsigned\n\ +integer, but does fit in a positive C int, it is silently truncated to\n\ +16-bit unsigned integer.\n\ +However, this silent truncation feature is deprecated, and will raise an \n\ +exception in future versions of Python."); static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 05:44:13 2016 From: python-checkins at python.org (xavier.degaye) Date: Sun, 02 Oct 2016 09:44:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzM4?= =?utf-8?q?=3A_Restore_test=5Fpdb_doctests=2E?= Message-ID: <20161002094413.82118.3438.146A2217@psf.io> https://hg.python.org/cpython/rev/7fe1f23ec60a changeset: 104243:7fe1f23ec60a branch: 3.6 parent: 104240:ac9734540eb7 user: Xavier de Gaye date: Sun Oct 02 11:42:22 2016 +0200 summary: Issue #28338: Restore test_pdb doctests. files: Lib/test/test_pdb.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1093,7 +1093,7 @@ def load_tests(*args): from test import test_pdb - suites = [unittest.makeSuite(PdbTestCase)] + suites = [unittest.makeSuite(PdbTestCase), doctest.DocTestSuite(test_pdb)] return unittest.TestSuite(suites) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 05:44:13 2016 From: python-checkins at python.org (xavier.degaye) Date: Sun, 02 Oct 2016 09:44:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328338=3A_Merge_from_3=2E6=2E?= Message-ID: <20161002094413.75730.66138.E8FDAF4C@psf.io> https://hg.python.org/cpython/rev/d23ac799fe83 changeset: 104244:d23ac799fe83 parent: 104242:3da460ca854b parent: 104243:7fe1f23ec60a user: Xavier de Gaye date: Sun Oct 02 11:43:25 2016 +0200 summary: Issue #28338: Merge from 3.6. files: Lib/test/test_pdb.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1093,7 +1093,7 @@ def load_tests(*args): from test import test_pdb - suites = [unittest.makeSuite(PdbTestCase)] + suites = [unittest.makeSuite(PdbTestCase), doctest.DocTestSuite(test_pdb)] return unittest.TestSuite(suites) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 06:06:33 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 10:06:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI3MzU4?= =?utf-8?q?=3A_Fix_typo_in_error_message?= Message-ID: <20161002100632.17319.14391.B4089468@psf.io> https://hg.python.org/cpython/rev/e2d4e077cfb2 changeset: 104245:e2d4e077cfb2 branch: 3.6 parent: 104243:7fe1f23ec60a user: Berker Peksag date: Sun Oct 02 13:08:25 2016 +0300 summary: Issue #27358: Fix typo in error message files: Python/ceval.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2721,7 +2721,7 @@ if (PyDict_Update(sum, arg) < 0) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping1", + "'%.200s' object is not a mapping", arg->ob_type->tp_name); } Py_DECREF(sum); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 06:06:45 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 10:06:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327358=3A_Merge_from_3=2E6?= Message-ID: <20161002100632.82256.41082.C35B8CD2@psf.io> https://hg.python.org/cpython/rev/9abb316f1593 changeset: 104246:9abb316f1593 parent: 104244:d23ac799fe83 parent: 104245:e2d4e077cfb2 user: Berker Peksag date: Sun Oct 02 13:08:47 2016 +0300 summary: Issue #27358: Merge from 3.6 files: Python/ceval.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2721,7 +2721,7 @@ if (PyDict_Update(sum, arg) < 0) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping1", + "'%.200s' object is not a mapping", arg->ob_type->tp_name); } Py_DECREF(sum); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 06:46:49 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 10:46:49 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjI3?= =?utf-8?q?=3A_gzip_now_supports_pathlib?= Message-ID: <20161002104649.5324.67726.E97FC272@psf.io> https://hg.python.org/cpython/rev/3f71d1a93053 changeset: 104247:3f71d1a93053 branch: 3.6 parent: 104245:e2d4e077cfb2 user: Berker Peksag date: Sun Oct 02 13:47:58 2016 +0300 summary: Issue #28227: gzip now supports pathlib Patch by Ethan Furman. files: Doc/library/gzip.rst | 5 +++++ Lib/gzip.py | 4 +++- Lib/test/test_gzip.py | 22 ++++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 32 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 @@ -56,6 +56,8 @@ .. versionchanged:: 3.4 Added support for the ``'x'``, ``'xb'`` and ``'xt'`` modes. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None) @@ -151,6 +153,9 @@ The :meth:`~io.BufferedIOBase.read` method now accepts an argument of ``None``. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + .. function:: compress(data, compresslevel=9) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -49,7 +49,7 @@ raise ValueError("Argument 'newline' not supported in binary mode") gz_mode = mode.replace("t", "") - if isinstance(filename, (str, bytes)): + if isinstance(filename, (str, bytes, os.PathLike)): binary_file = GzipFile(filename, gz_mode, compresslevel) elif hasattr(filename, "read") or hasattr(filename, "write"): binary_file = GzipFile(None, gz_mode, compresslevel, filename) @@ -165,6 +165,8 @@ filename = getattr(fileobj, 'name', '') if not isinstance(filename, (str, bytes)): filename = '' + else: + filename = os.fspath(filename) if mode is None: mode = getattr(fileobj, 'mode', 'rb') 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 @@ -5,6 +5,7 @@ from test import support from test.support import bigmemtest, _4G import os +import pathlib import io import struct import array @@ -67,6 +68,18 @@ # Test multiple close() calls. f.close() + def test_write_read_with_pathlike_file(self): + filename = pathlib.Path(self.filename) + with gzip.GzipFile(filename, 'w') as f: + f.write(data1 * 50) + self.assertIsInstance(f.name, str) + with gzip.GzipFile(filename, 'a') as f: + f.write(data1) + with gzip.GzipFile(filename) as f: + d = f.read() + self.assertEqual(d, data1 * 51) + self.assertIsInstance(f.name, str) + # The following test_write_xy methods test that write accepts # the corresponding bytes-like object type as input # and that the data written equals bytes(xy) in all cases. @@ -521,6 +534,15 @@ file_data = gzip.decompress(f.read()) self.assertEqual(file_data, uncompressed) + def test_pathlike_file(self): + filename = pathlib.Path(self.filename) + with gzip.open(filename, "wb") as f: + f.write(data1 * 50) + with gzip.open(filename, "ab") as f: + f.write(data1) + with gzip.open(filename) as f: + self.assertEqual(f.read(), data1 * 51) + def test_implicit_binary_modes(self): # Test implicit binary modes (no "b" or "t" in mode string). uncompressed = data1 * 50 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,8 @@ Library ------- +- Issue #28227: gzip now supports pathlib. Patch by Ethan Furman. + - Issue #27358: Optimized merging var-keyword arguments and improved error message when pass a non-mapping as a var-keyword argument. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 06:46:50 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 10:46:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328227=3A_Merge_from_3=2E6?= Message-ID: <20161002104650.82206.86166.1C86320E@psf.io> https://hg.python.org/cpython/rev/b244bf74b638 changeset: 104248:b244bf74b638 parent: 104246:9abb316f1593 parent: 104247:3f71d1a93053 user: Berker Peksag date: Sun Oct 02 13:49:05 2016 +0300 summary: Issue #28227: Merge from 3.6 files: Doc/library/gzip.rst | 5 +++++ Lib/gzip.py | 4 +++- Lib/test/test_gzip.py | 22 ++++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 32 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 @@ -56,6 +56,8 @@ .. versionchanged:: 3.4 Added support for the ``'x'``, ``'xb'`` and ``'xt'`` modes. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None) @@ -151,6 +153,9 @@ The :meth:`~io.BufferedIOBase.read` method now accepts an argument of ``None``. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + .. function:: compress(data, compresslevel=9) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -49,7 +49,7 @@ raise ValueError("Argument 'newline' not supported in binary mode") gz_mode = mode.replace("t", "") - if isinstance(filename, (str, bytes)): + if isinstance(filename, (str, bytes, os.PathLike)): binary_file = GzipFile(filename, gz_mode, compresslevel) elif hasattr(filename, "read") or hasattr(filename, "write"): binary_file = GzipFile(None, gz_mode, compresslevel, filename) @@ -165,6 +165,8 @@ filename = getattr(fileobj, 'name', '') if not isinstance(filename, (str, bytes)): filename = '' + else: + filename = os.fspath(filename) if mode is None: mode = getattr(fileobj, 'mode', 'rb') 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 @@ -5,6 +5,7 @@ from test import support from test.support import bigmemtest, _4G import os +import pathlib import io import struct import array @@ -67,6 +68,18 @@ # Test multiple close() calls. f.close() + def test_write_read_with_pathlike_file(self): + filename = pathlib.Path(self.filename) + with gzip.GzipFile(filename, 'w') as f: + f.write(data1 * 50) + self.assertIsInstance(f.name, str) + with gzip.GzipFile(filename, 'a') as f: + f.write(data1) + with gzip.GzipFile(filename) as f: + d = f.read() + self.assertEqual(d, data1 * 51) + self.assertIsInstance(f.name, str) + # The following test_write_xy methods test that write accepts # the corresponding bytes-like object type as input # and that the data written equals bytes(xy) in all cases. @@ -521,6 +534,15 @@ file_data = gzip.decompress(f.read()) self.assertEqual(file_data, uncompressed) + def test_pathlike_file(self): + filename = pathlib.Path(self.filename) + with gzip.open(filename, "wb") as f: + f.write(data1 * 50) + with gzip.open(filename, "ab") as f: + f.write(data1) + with gzip.open(filename) as f: + self.assertEqual(f.read(), data1 * 51) + def test_implicit_binary_modes(self): # Test implicit binary modes (no "b" or "t" in mode string). uncompressed = data1 * 50 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,8 @@ Library ------- +- Issue #28227: gzip now supports pathlib. Patch by Ethan Furman. + - Issue #28332: Deprecated silent truncations in socket.htons and socket.ntohs. Original patch by Oren Milman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 13:05:20 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 17:05:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjI1?= =?utf-8?q?=3A_bz2_module_now_supports_pathlib?= Message-ID: <20161002170520.20698.83131.C116BE76@psf.io> https://hg.python.org/cpython/rev/fc0c244c6e79 changeset: 104249:fc0c244c6e79 branch: 3.6 parent: 104247:3f71d1a93053 user: Berker Peksag date: Sun Oct 02 20:07:06 2016 +0300 summary: Issue #28225: bz2 module now supports pathlib Initial patch by Ethan Furman. files: Doc/library/bz2.rst | 6 ++++++ Lib/bz2.py | 16 +++++++++------- Lib/test/test_bz2.py | 8 ++++++++ Misc/NEWS | 2 ++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -61,6 +61,9 @@ .. versionchanged:: 3.4 The ``'x'`` (exclusive creation) mode was added. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + .. class:: BZ2File(filename, mode='r', buffering=None, compresslevel=9) @@ -128,6 +131,9 @@ The :meth:`~io.BufferedIOBase.read` method now accepts an argument of ``None``. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + Incremental (de)compression --------------------------- diff --git a/Lib/bz2.py b/Lib/bz2.py --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -11,6 +11,7 @@ from builtins import open as _builtin_open import io +import os import warnings import _compression @@ -42,9 +43,9 @@ def __init__(self, filename, mode="r", buffering=None, compresslevel=9): """Open a bzip2-compressed file. - If filename is a str or bytes object, it gives the name - of the file to be opened. Otherwise, it should be a file object, - which will be used to read or write the compressed data. + If filename is a str, bytes, or PathLike object, it gives the + name of the file to be opened. Otherwise, it should be a file + object, which will be used to read or write the compressed data. mode can be 'r' for reading (default), 'w' for (over)writing, 'x' for creating exclusively, or 'a' for appending. These can @@ -91,7 +92,7 @@ else: raise ValueError("Invalid mode: %r" % (mode,)) - if isinstance(filename, (str, bytes)): + if isinstance(filename, (str, bytes, os.PathLike)): self._fp = _builtin_open(filename, mode) self._closefp = True self._mode = mode_code @@ -99,7 +100,7 @@ self._fp = filename self._mode = mode_code else: - raise TypeError("filename must be a str or bytes object, or a file") + raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: raw = _compression.DecompressReader(self._fp, @@ -289,8 +290,9 @@ encoding=None, errors=None, newline=None): """Open a bzip2-compressed file in binary or text mode. - The filename argument can be an actual filename (a str or bytes - object), or an existing file object to read from or write to. + The filename argument can be an actual filename (a str, bytes, or + PathLike object), or an existing file object to read from or write + to. The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or "ab" for binary mode, or "rt", "wt", "xt" or "at" for text mode. 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 @@ -6,6 +6,7 @@ import os import pickle import glob +import pathlib import random import subprocess import sys @@ -560,6 +561,13 @@ with BZ2File(str_filename, "rb") as f: self.assertEqual(f.read(), self.DATA) + def testOpenPathLikeFilename(self): + filename = pathlib.Path(self.filename) + with BZ2File(filename, "wb") as f: + f.write(self.DATA) + with BZ2File(filename, "rb") as f: + self.assertEqual(f.read(), self.DATA) + def testDecompressLimited(self): """Decompressed data buffering should be limited""" bomb = bz2.compress(b'\0' * int(2e6), compresslevel=9) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,8 @@ Library ------- +- Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. + - Issue #28227: gzip now supports pathlib. Patch by Ethan Furman. - Issue #27358: Optimized merging var-keyword arguments and improved error -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 13:05:20 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 02 Oct 2016 17:05:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328225=3A_Merge_from_3=2E6?= Message-ID: <20161002170520.5035.81407.8971B8DA@psf.io> https://hg.python.org/cpython/rev/0e9b77424d10 changeset: 104250:0e9b77424d10 parent: 104248:b244bf74b638 parent: 104249:fc0c244c6e79 user: Berker Peksag date: Sun Oct 02 20:07:38 2016 +0300 summary: Issue #28225: Merge from 3.6 files: Doc/library/bz2.rst | 6 ++++++ Lib/bz2.py | 16 +++++++++------- Lib/test/test_bz2.py | 8 ++++++++ Misc/NEWS | 2 ++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -61,6 +61,9 @@ .. versionchanged:: 3.4 The ``'x'`` (exclusive creation) mode was added. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + .. class:: BZ2File(filename, mode='r', buffering=None, compresslevel=9) @@ -128,6 +131,9 @@ The :meth:`~io.BufferedIOBase.read` method now accepts an argument of ``None``. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + Incremental (de)compression --------------------------- diff --git a/Lib/bz2.py b/Lib/bz2.py --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -11,6 +11,7 @@ from builtins import open as _builtin_open import io +import os import warnings import _compression @@ -42,9 +43,9 @@ def __init__(self, filename, mode="r", buffering=None, compresslevel=9): """Open a bzip2-compressed file. - If filename is a str or bytes object, it gives the name - of the file to be opened. Otherwise, it should be a file object, - which will be used to read or write the compressed data. + If filename is a str, bytes, or PathLike object, it gives the + name of the file to be opened. Otherwise, it should be a file + object, which will be used to read or write the compressed data. mode can be 'r' for reading (default), 'w' for (over)writing, 'x' for creating exclusively, or 'a' for appending. These can @@ -91,7 +92,7 @@ else: raise ValueError("Invalid mode: %r" % (mode,)) - if isinstance(filename, (str, bytes)): + if isinstance(filename, (str, bytes, os.PathLike)): self._fp = _builtin_open(filename, mode) self._closefp = True self._mode = mode_code @@ -99,7 +100,7 @@ self._fp = filename self._mode = mode_code else: - raise TypeError("filename must be a str or bytes object, or a file") + raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: raw = _compression.DecompressReader(self._fp, @@ -289,8 +290,9 @@ encoding=None, errors=None, newline=None): """Open a bzip2-compressed file in binary or text mode. - The filename argument can be an actual filename (a str or bytes - object), or an existing file object to read from or write to. + The filename argument can be an actual filename (a str, bytes, or + PathLike object), or an existing file object to read from or write + to. The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or "ab" for binary mode, or "rt", "wt", "xt" or "at" for text mode. 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 @@ -6,6 +6,7 @@ import os import pickle import glob +import pathlib import random import subprocess import sys @@ -560,6 +561,13 @@ with BZ2File(str_filename, "rb") as f: self.assertEqual(f.read(), self.DATA) + def testOpenPathLikeFilename(self): + filename = pathlib.Path(self.filename) + with BZ2File(filename, "wb") as f: + f.write(self.DATA) + with BZ2File(filename, "rb") as f: + self.assertEqual(f.read(), self.DATA) + def testDecompressLimited(self): """Decompressed data buffering should be limited""" bomb = bz2.compress(b'\0' * int(2e6), compresslevel=9) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,8 @@ Library ------- +- Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. + - Issue #28227: gzip now supports pathlib. Patch by Ethan Furman. - Issue #28332: Deprecated silent truncations in socket.htons and socket.ntohs. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Moved_Unicode_?= =?utf-8?q?C_API_related_tests_to_separate_test_class=2E?= Message-ID: <20161002183121.20991.53438.25EE84B7@psf.io> https://hg.python.org/cpython/rev/a0b9c4f98573 changeset: 104251:a0b9c4f98573 branch: 2.7 parent: 104236:29a658d47ae8 user: Serhiy Storchaka date: Sun Oct 02 21:16:28 2016 +0300 summary: Moved Unicode C API related tests to separate test class. files: Lib/test/test_unicode.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) 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 @@ -1665,6 +1665,13 @@ self.assertEqual("%s" % u, u'__unicode__ overridden') self.assertEqual("{}".format(u), '__unicode__ overridden') + def test_free_after_iterating(self): + test_support.check_free_after_iterating(self, iter, unicode) + test_support.check_free_after_iterating(self, reversed, unicode) + + +class CAPITest(unittest.TestCase): + # Test PyUnicode_FromFormat() def test_from_format(self): test_support.import_module('ctypes') @@ -1857,11 +1864,6 @@ unicode_encodedecimal(u"123" + s, "xmlcharrefreplace"), '123' + exp) - def test_free_after_iterating(self): - test_support.check_free_after_iterating(self, iter, unicode) - test_support.check_free_after_iterating(self, reversed, unicode) - - def test_main(): test_support.run_unittest(__name__) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Moved_Unicode_C_API_related_tests_to_separate_test_class=2E?= Message-ID: <20161002183122.95050.80746.D8ABBCB5@psf.io> https://hg.python.org/cpython/rev/05788a9a0b88 changeset: 104253:05788a9a0b88 branch: 3.6 parent: 104249:fc0c244c6e79 parent: 104252:6dc423b2d929 user: Serhiy Storchaka date: Sun Oct 02 21:18:14 2016 +0300 summary: Moved Unicode C API related tests to separate test class. files: Lib/test/test_unicode.py | 231 +++++++++++++------------- 1 files changed, 117 insertions(+), 114 deletions(-) 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 @@ -2299,6 +2299,123 @@ self.assertEqual("%s" % s, '__str__ overridden') self.assertEqual("{}".format(s), '__str__ overridden') + def test_subclass_add(self): + class S(str): + def __add__(self, o): + return "3" + self.assertEqual(S("4") + S("5"), "3") + class S(str): + def __iadd__(self, o): + return "3" + s = S("1") + s += "4" + self.assertEqual(s, "3") + + def test_getnewargs(self): + text = 'abc' + args = text.__getnewargs__() + self.assertIsNot(args[0], text) + self.assertEqual(args[0], text) + self.assertEqual(len(args), 1) + + def test_resize(self): + for length in range(1, 100, 7): + # generate a fresh string (refcount=1) + text = 'a' * length + 'b' + + with support.check_warnings(('unicode_internal codec has been ' + 'deprecated', DeprecationWarning)): + # fill wstr internal field + abc = text.encode('unicode_internal') + self.assertEqual(abc.decode('unicode_internal'), text) + + # resize text: wstr field must be cleared and then recomputed + text += 'c' + abcdef = text.encode('unicode_internal') + self.assertNotEqual(abc, abcdef) + self.assertEqual(abcdef.decode('unicode_internal'), text) + + def test_compare(self): + # Issue #17615 + N = 10 + ascii = 'a' * N + ascii2 = 'z' * N + latin = '\x80' * N + latin2 = '\xff' * N + bmp = '\u0100' * N + bmp2 = '\uffff' * N + astral = '\U00100000' * N + astral2 = '\U0010ffff' * N + strings = ( + ascii, ascii2, + latin, latin2, + bmp, bmp2, + astral, astral2) + for text1, text2 in itertools.combinations(strings, 2): + equal = (text1 is text2) + self.assertEqual(text1 == text2, equal) + self.assertEqual(text1 != text2, not equal) + + if equal: + self.assertTrue(text1 <= text2) + self.assertTrue(text1 >= text2) + + # text1 is text2: duplicate strings to skip the "str1 == str2" + # optimization in unicode_compare_eq() and really compare + # character per character + copy1 = duplicate_string(text1) + copy2 = duplicate_string(text2) + self.assertIsNot(copy1, copy2) + + self.assertTrue(copy1 == copy2) + self.assertFalse(copy1 != copy2) + + self.assertTrue(copy1 <= copy2) + self.assertTrue(copy2 >= copy2) + + self.assertTrue(ascii < ascii2) + self.assertTrue(ascii < latin) + self.assertTrue(ascii < bmp) + self.assertTrue(ascii < astral) + self.assertFalse(ascii >= ascii2) + self.assertFalse(ascii >= latin) + self.assertFalse(ascii >= bmp) + self.assertFalse(ascii >= astral) + + self.assertFalse(latin < ascii) + self.assertTrue(latin < latin2) + self.assertTrue(latin < bmp) + self.assertTrue(latin < astral) + self.assertTrue(latin >= ascii) + self.assertFalse(latin >= latin2) + self.assertFalse(latin >= bmp) + self.assertFalse(latin >= astral) + + self.assertFalse(bmp < ascii) + self.assertFalse(bmp < latin) + self.assertTrue(bmp < bmp2) + self.assertTrue(bmp < astral) + self.assertTrue(bmp >= ascii) + self.assertTrue(bmp >= latin) + self.assertFalse(bmp >= bmp2) + self.assertFalse(bmp >= astral) + + self.assertFalse(astral < ascii) + self.assertFalse(astral < latin) + self.assertFalse(astral < bmp2) + self.assertTrue(astral < astral2) + self.assertTrue(astral >= ascii) + self.assertTrue(astral >= latin) + self.assertTrue(astral >= bmp2) + self.assertFalse(astral >= astral2) + + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, str) + support.check_free_after_iterating(self, reversed, str) + + +class CAPITest(unittest.TestCase): + # Test PyUnicode_FromFormat() def test_from_format(self): support.import_module('ctypes') @@ -2594,18 +2711,6 @@ self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') - def test_subclass_add(self): - class S(str): - def __add__(self, o): - return "3" - self.assertEqual(S("4") + S("5"), "3") - class S(str): - def __iadd__(self, o): - return "3" - s = S("1") - s += "4" - self.assertEqual(s, "3") - @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal @@ -2634,104 +2739,6 @@ self.assertEqual(transform_decimal('123\u20ac'), '123\u20ac') - def test_getnewargs(self): - text = 'abc' - args = text.__getnewargs__() - self.assertIsNot(args[0], text) - self.assertEqual(args[0], text) - self.assertEqual(len(args), 1) - - def test_resize(self): - for length in range(1, 100, 7): - # generate a fresh string (refcount=1) - text = 'a' * length + 'b' - - with support.check_warnings(('unicode_internal codec has been ' - 'deprecated', DeprecationWarning)): - # fill wstr internal field - abc = text.encode('unicode_internal') - self.assertEqual(abc.decode('unicode_internal'), text) - - # resize text: wstr field must be cleared and then recomputed - text += 'c' - abcdef = text.encode('unicode_internal') - self.assertNotEqual(abc, abcdef) - self.assertEqual(abcdef.decode('unicode_internal'), text) - - def test_compare(self): - # Issue #17615 - N = 10 - ascii = 'a' * N - ascii2 = 'z' * N - latin = '\x80' * N - latin2 = '\xff' * N - bmp = '\u0100' * N - bmp2 = '\uffff' * N - astral = '\U00100000' * N - astral2 = '\U0010ffff' * N - strings = ( - ascii, ascii2, - latin, latin2, - bmp, bmp2, - astral, astral2) - for text1, text2 in itertools.combinations(strings, 2): - equal = (text1 is text2) - self.assertEqual(text1 == text2, equal) - self.assertEqual(text1 != text2, not equal) - - if equal: - self.assertTrue(text1 <= text2) - self.assertTrue(text1 >= text2) - - # text1 is text2: duplicate strings to skip the "str1 == str2" - # optimization in unicode_compare_eq() and really compare - # character per character - copy1 = duplicate_string(text1) - copy2 = duplicate_string(text2) - self.assertIsNot(copy1, copy2) - - self.assertTrue(copy1 == copy2) - self.assertFalse(copy1 != copy2) - - self.assertTrue(copy1 <= copy2) - self.assertTrue(copy2 >= copy2) - - self.assertTrue(ascii < ascii2) - self.assertTrue(ascii < latin) - self.assertTrue(ascii < bmp) - self.assertTrue(ascii < astral) - self.assertFalse(ascii >= ascii2) - self.assertFalse(ascii >= latin) - self.assertFalse(ascii >= bmp) - self.assertFalse(ascii >= astral) - - self.assertFalse(latin < ascii) - self.assertTrue(latin < latin2) - self.assertTrue(latin < bmp) - self.assertTrue(latin < astral) - self.assertTrue(latin >= ascii) - self.assertFalse(latin >= latin2) - self.assertFalse(latin >= bmp) - self.assertFalse(latin >= astral) - - self.assertFalse(bmp < ascii) - self.assertFalse(bmp < latin) - self.assertTrue(bmp < bmp2) - self.assertTrue(bmp < astral) - self.assertTrue(bmp >= ascii) - self.assertTrue(bmp >= latin) - self.assertFalse(bmp >= bmp2) - self.assertFalse(bmp >= astral) - - self.assertFalse(astral < ascii) - self.assertFalse(astral < latin) - self.assertFalse(astral < bmp2) - self.assertTrue(astral < astral2) - self.assertTrue(astral >= ascii) - self.assertTrue(astral >= latin) - self.assertTrue(astral >= bmp2) - self.assertFalse(astral >= astral2) - @support.cpython_only def test_pep393_utf8_caching_bug(self): # Issue #25709: Problem with string concatenation and utf-8 cache @@ -2749,10 +2756,6 @@ # Check that the second call returns the same result self.assertEqual(getargs_s_hash(s), chr(k).encode() * (i + 1)) - def test_free_after_iterating(self): - support.check_free_after_iterating(self, iter, str) - support.check_free_after_iterating(self, reversed, str) - def test_invalid_sequences(self): for letter in string.ascii_letters + "89": # 0-7 are octal escapes if letter in "abfnrtuvxNU": -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Moved_Unicode_?= =?utf-8?q?C_API_related_tests_to_separate_test_class=2E?= Message-ID: <20161002183121.1522.51479.8862C076@psf.io> https://hg.python.org/cpython/rev/6dc423b2d929 changeset: 104252:6dc423b2d929 branch: 3.5 parent: 104239:6406322f4749 user: Serhiy Storchaka date: Sun Oct 02 21:16:38 2016 +0300 summary: Moved Unicode C API related tests to separate test class. files: Lib/test/test_unicode.py | 231 +++++++++++++------------- 1 files changed, 117 insertions(+), 114 deletions(-) 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 @@ -2275,6 +2275,123 @@ self.assertEqual("%s" % s, '__str__ overridden') self.assertEqual("{}".format(s), '__str__ overridden') + def test_subclass_add(self): + class S(str): + def __add__(self, o): + return "3" + self.assertEqual(S("4") + S("5"), "3") + class S(str): + def __iadd__(self, o): + return "3" + s = S("1") + s += "4" + self.assertEqual(s, "3") + + def test_getnewargs(self): + text = 'abc' + args = text.__getnewargs__() + self.assertIsNot(args[0], text) + self.assertEqual(args[0], text) + self.assertEqual(len(args), 1) + + def test_resize(self): + for length in range(1, 100, 7): + # generate a fresh string (refcount=1) + text = 'a' * length + 'b' + + with support.check_warnings(('unicode_internal codec has been ' + 'deprecated', DeprecationWarning)): + # fill wstr internal field + abc = text.encode('unicode_internal') + self.assertEqual(abc.decode('unicode_internal'), text) + + # resize text: wstr field must be cleared and then recomputed + text += 'c' + abcdef = text.encode('unicode_internal') + self.assertNotEqual(abc, abcdef) + self.assertEqual(abcdef.decode('unicode_internal'), text) + + def test_compare(self): + # Issue #17615 + N = 10 + ascii = 'a' * N + ascii2 = 'z' * N + latin = '\x80' * N + latin2 = '\xff' * N + bmp = '\u0100' * N + bmp2 = '\uffff' * N + astral = '\U00100000' * N + astral2 = '\U0010ffff' * N + strings = ( + ascii, ascii2, + latin, latin2, + bmp, bmp2, + astral, astral2) + for text1, text2 in itertools.combinations(strings, 2): + equal = (text1 is text2) + self.assertEqual(text1 == text2, equal) + self.assertEqual(text1 != text2, not equal) + + if equal: + self.assertTrue(text1 <= text2) + self.assertTrue(text1 >= text2) + + # text1 is text2: duplicate strings to skip the "str1 == str2" + # optimization in unicode_compare_eq() and really compare + # character per character + copy1 = duplicate_string(text1) + copy2 = duplicate_string(text2) + self.assertIsNot(copy1, copy2) + + self.assertTrue(copy1 == copy2) + self.assertFalse(copy1 != copy2) + + self.assertTrue(copy1 <= copy2) + self.assertTrue(copy2 >= copy2) + + self.assertTrue(ascii < ascii2) + self.assertTrue(ascii < latin) + self.assertTrue(ascii < bmp) + self.assertTrue(ascii < astral) + self.assertFalse(ascii >= ascii2) + self.assertFalse(ascii >= latin) + self.assertFalse(ascii >= bmp) + self.assertFalse(ascii >= astral) + + self.assertFalse(latin < ascii) + self.assertTrue(latin < latin2) + self.assertTrue(latin < bmp) + self.assertTrue(latin < astral) + self.assertTrue(latin >= ascii) + self.assertFalse(latin >= latin2) + self.assertFalse(latin >= bmp) + self.assertFalse(latin >= astral) + + self.assertFalse(bmp < ascii) + self.assertFalse(bmp < latin) + self.assertTrue(bmp < bmp2) + self.assertTrue(bmp < astral) + self.assertTrue(bmp >= ascii) + self.assertTrue(bmp >= latin) + self.assertFalse(bmp >= bmp2) + self.assertFalse(bmp >= astral) + + self.assertFalse(astral < ascii) + self.assertFalse(astral < latin) + self.assertFalse(astral < bmp2) + self.assertTrue(astral < astral2) + self.assertTrue(astral >= ascii) + self.assertTrue(astral >= latin) + self.assertTrue(astral >= bmp2) + self.assertFalse(astral >= astral2) + + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, str) + support.check_free_after_iterating(self, reversed, str) + + +class CAPITest(unittest.TestCase): + # Test PyUnicode_FromFormat() def test_from_format(self): support.import_module('ctypes') @@ -2570,18 +2687,6 @@ self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') - def test_subclass_add(self): - class S(str): - def __add__(self, o): - return "3" - self.assertEqual(S("4") + S("5"), "3") - class S(str): - def __iadd__(self, o): - return "3" - s = S("1") - s += "4" - self.assertEqual(s, "3") - @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal @@ -2610,104 +2715,6 @@ self.assertEqual(transform_decimal('123\u20ac'), '123\u20ac') - def test_getnewargs(self): - text = 'abc' - args = text.__getnewargs__() - self.assertIsNot(args[0], text) - self.assertEqual(args[0], text) - self.assertEqual(len(args), 1) - - def test_resize(self): - for length in range(1, 100, 7): - # generate a fresh string (refcount=1) - text = 'a' * length + 'b' - - with support.check_warnings(('unicode_internal codec has been ' - 'deprecated', DeprecationWarning)): - # fill wstr internal field - abc = text.encode('unicode_internal') - self.assertEqual(abc.decode('unicode_internal'), text) - - # resize text: wstr field must be cleared and then recomputed - text += 'c' - abcdef = text.encode('unicode_internal') - self.assertNotEqual(abc, abcdef) - self.assertEqual(abcdef.decode('unicode_internal'), text) - - def test_compare(self): - # Issue #17615 - N = 10 - ascii = 'a' * N - ascii2 = 'z' * N - latin = '\x80' * N - latin2 = '\xff' * N - bmp = '\u0100' * N - bmp2 = '\uffff' * N - astral = '\U00100000' * N - astral2 = '\U0010ffff' * N - strings = ( - ascii, ascii2, - latin, latin2, - bmp, bmp2, - astral, astral2) - for text1, text2 in itertools.combinations(strings, 2): - equal = (text1 is text2) - self.assertEqual(text1 == text2, equal) - self.assertEqual(text1 != text2, not equal) - - if equal: - self.assertTrue(text1 <= text2) - self.assertTrue(text1 >= text2) - - # text1 is text2: duplicate strings to skip the "str1 == str2" - # optimization in unicode_compare_eq() and really compare - # character per character - copy1 = duplicate_string(text1) - copy2 = duplicate_string(text2) - self.assertIsNot(copy1, copy2) - - self.assertTrue(copy1 == copy2) - self.assertFalse(copy1 != copy2) - - self.assertTrue(copy1 <= copy2) - self.assertTrue(copy2 >= copy2) - - self.assertTrue(ascii < ascii2) - self.assertTrue(ascii < latin) - self.assertTrue(ascii < bmp) - self.assertTrue(ascii < astral) - self.assertFalse(ascii >= ascii2) - self.assertFalse(ascii >= latin) - self.assertFalse(ascii >= bmp) - self.assertFalse(ascii >= astral) - - self.assertFalse(latin < ascii) - self.assertTrue(latin < latin2) - self.assertTrue(latin < bmp) - self.assertTrue(latin < astral) - self.assertTrue(latin >= ascii) - self.assertFalse(latin >= latin2) - self.assertFalse(latin >= bmp) - self.assertFalse(latin >= astral) - - self.assertFalse(bmp < ascii) - self.assertFalse(bmp < latin) - self.assertTrue(bmp < bmp2) - self.assertTrue(bmp < astral) - self.assertTrue(bmp >= ascii) - self.assertTrue(bmp >= latin) - self.assertFalse(bmp >= bmp2) - self.assertFalse(bmp >= astral) - - self.assertFalse(astral < ascii) - self.assertFalse(astral < latin) - self.assertFalse(astral < bmp2) - self.assertTrue(astral < astral2) - self.assertTrue(astral >= ascii) - self.assertTrue(astral >= latin) - self.assertTrue(astral >= bmp2) - self.assertFalse(astral >= astral2) - @support.cpython_only def test_pep393_utf8_caching_bug(self): # Issue #25709: Problem with string concatenation and utf-8 cache @@ -2725,10 +2732,6 @@ # Check that the second call returns the same result self.assertEqual(getargs_s_hash(s), chr(k).encode() * (i + 1)) - def test_free_after_iterating(self): - support.check_free_after_iterating(self, iter, str) - support.check_free_after_iterating(self, reversed, str) - class StringModuleTest(unittest.TestCase): def test_formatter_parser(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Moved_Unicode_C_API_related_tests_to_separate_test_class?= =?utf-8?q?=2E?= Message-ID: <20161002183122.76110.24131.8219D342@psf.io> https://hg.python.org/cpython/rev/343b888a3471 changeset: 104254:343b888a3471 parent: 104250:0e9b77424d10 parent: 104253:05788a9a0b88 user: Serhiy Storchaka date: Sun Oct 02 21:19:38 2016 +0300 summary: Moved Unicode C API related tests to separate test class. files: Lib/test/test_unicode.py | 231 +++++++++++++------------- 1 files changed, 117 insertions(+), 114 deletions(-) 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 @@ -2299,6 +2299,123 @@ self.assertEqual("%s" % s, '__str__ overridden') self.assertEqual("{}".format(s), '__str__ overridden') + def test_subclass_add(self): + class S(str): + def __add__(self, o): + return "3" + self.assertEqual(S("4") + S("5"), "3") + class S(str): + def __iadd__(self, o): + return "3" + s = S("1") + s += "4" + self.assertEqual(s, "3") + + def test_getnewargs(self): + text = 'abc' + args = text.__getnewargs__() + self.assertIsNot(args[0], text) + self.assertEqual(args[0], text) + self.assertEqual(len(args), 1) + + def test_resize(self): + for length in range(1, 100, 7): + # generate a fresh string (refcount=1) + text = 'a' * length + 'b' + + with support.check_warnings(('unicode_internal codec has been ' + 'deprecated', DeprecationWarning)): + # fill wstr internal field + abc = text.encode('unicode_internal') + self.assertEqual(abc.decode('unicode_internal'), text) + + # resize text: wstr field must be cleared and then recomputed + text += 'c' + abcdef = text.encode('unicode_internal') + self.assertNotEqual(abc, abcdef) + self.assertEqual(abcdef.decode('unicode_internal'), text) + + def test_compare(self): + # Issue #17615 + N = 10 + ascii = 'a' * N + ascii2 = 'z' * N + latin = '\x80' * N + latin2 = '\xff' * N + bmp = '\u0100' * N + bmp2 = '\uffff' * N + astral = '\U00100000' * N + astral2 = '\U0010ffff' * N + strings = ( + ascii, ascii2, + latin, latin2, + bmp, bmp2, + astral, astral2) + for text1, text2 in itertools.combinations(strings, 2): + equal = (text1 is text2) + self.assertEqual(text1 == text2, equal) + self.assertEqual(text1 != text2, not equal) + + if equal: + self.assertTrue(text1 <= text2) + self.assertTrue(text1 >= text2) + + # text1 is text2: duplicate strings to skip the "str1 == str2" + # optimization in unicode_compare_eq() and really compare + # character per character + copy1 = duplicate_string(text1) + copy2 = duplicate_string(text2) + self.assertIsNot(copy1, copy2) + + self.assertTrue(copy1 == copy2) + self.assertFalse(copy1 != copy2) + + self.assertTrue(copy1 <= copy2) + self.assertTrue(copy2 >= copy2) + + self.assertTrue(ascii < ascii2) + self.assertTrue(ascii < latin) + self.assertTrue(ascii < bmp) + self.assertTrue(ascii < astral) + self.assertFalse(ascii >= ascii2) + self.assertFalse(ascii >= latin) + self.assertFalse(ascii >= bmp) + self.assertFalse(ascii >= astral) + + self.assertFalse(latin < ascii) + self.assertTrue(latin < latin2) + self.assertTrue(latin < bmp) + self.assertTrue(latin < astral) + self.assertTrue(latin >= ascii) + self.assertFalse(latin >= latin2) + self.assertFalse(latin >= bmp) + self.assertFalse(latin >= astral) + + self.assertFalse(bmp < ascii) + self.assertFalse(bmp < latin) + self.assertTrue(bmp < bmp2) + self.assertTrue(bmp < astral) + self.assertTrue(bmp >= ascii) + self.assertTrue(bmp >= latin) + self.assertFalse(bmp >= bmp2) + self.assertFalse(bmp >= astral) + + self.assertFalse(astral < ascii) + self.assertFalse(astral < latin) + self.assertFalse(astral < bmp2) + self.assertTrue(astral < astral2) + self.assertTrue(astral >= ascii) + self.assertTrue(astral >= latin) + self.assertTrue(astral >= bmp2) + self.assertFalse(astral >= astral2) + + def test_free_after_iterating(self): + support.check_free_after_iterating(self, iter, str) + support.check_free_after_iterating(self, reversed, str) + + +class CAPITest(unittest.TestCase): + # Test PyUnicode_FromFormat() def test_from_format(self): support.import_module('ctypes') @@ -2594,18 +2711,6 @@ self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') - def test_subclass_add(self): - class S(str): - def __add__(self, o): - return "3" - self.assertEqual(S("4") + S("5"), "3") - class S(str): - def __iadd__(self, o): - return "3" - s = S("1") - s += "4" - self.assertEqual(s, "3") - @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal @@ -2634,104 +2739,6 @@ self.assertEqual(transform_decimal('123\u20ac'), '123\u20ac') - def test_getnewargs(self): - text = 'abc' - args = text.__getnewargs__() - self.assertIsNot(args[0], text) - self.assertEqual(args[0], text) - self.assertEqual(len(args), 1) - - def test_resize(self): - for length in range(1, 100, 7): - # generate a fresh string (refcount=1) - text = 'a' * length + 'b' - - with support.check_warnings(('unicode_internal codec has been ' - 'deprecated', DeprecationWarning)): - # fill wstr internal field - abc = text.encode('unicode_internal') - self.assertEqual(abc.decode('unicode_internal'), text) - - # resize text: wstr field must be cleared and then recomputed - text += 'c' - abcdef = text.encode('unicode_internal') - self.assertNotEqual(abc, abcdef) - self.assertEqual(abcdef.decode('unicode_internal'), text) - - def test_compare(self): - # Issue #17615 - N = 10 - ascii = 'a' * N - ascii2 = 'z' * N - latin = '\x80' * N - latin2 = '\xff' * N - bmp = '\u0100' * N - bmp2 = '\uffff' * N - astral = '\U00100000' * N - astral2 = '\U0010ffff' * N - strings = ( - ascii, ascii2, - latin, latin2, - bmp, bmp2, - astral, astral2) - for text1, text2 in itertools.combinations(strings, 2): - equal = (text1 is text2) - self.assertEqual(text1 == text2, equal) - self.assertEqual(text1 != text2, not equal) - - if equal: - self.assertTrue(text1 <= text2) - self.assertTrue(text1 >= text2) - - # text1 is text2: duplicate strings to skip the "str1 == str2" - # optimization in unicode_compare_eq() and really compare - # character per character - copy1 = duplicate_string(text1) - copy2 = duplicate_string(text2) - self.assertIsNot(copy1, copy2) - - self.assertTrue(copy1 == copy2) - self.assertFalse(copy1 != copy2) - - self.assertTrue(copy1 <= copy2) - self.assertTrue(copy2 >= copy2) - - self.assertTrue(ascii < ascii2) - self.assertTrue(ascii < latin) - self.assertTrue(ascii < bmp) - self.assertTrue(ascii < astral) - self.assertFalse(ascii >= ascii2) - self.assertFalse(ascii >= latin) - self.assertFalse(ascii >= bmp) - self.assertFalse(ascii >= astral) - - self.assertFalse(latin < ascii) - self.assertTrue(latin < latin2) - self.assertTrue(latin < bmp) - self.assertTrue(latin < astral) - self.assertTrue(latin >= ascii) - self.assertFalse(latin >= latin2) - self.assertFalse(latin >= bmp) - self.assertFalse(latin >= astral) - - self.assertFalse(bmp < ascii) - self.assertFalse(bmp < latin) - self.assertTrue(bmp < bmp2) - self.assertTrue(bmp < astral) - self.assertTrue(bmp >= ascii) - self.assertTrue(bmp >= latin) - self.assertFalse(bmp >= bmp2) - self.assertFalse(bmp >= astral) - - self.assertFalse(astral < ascii) - self.assertFalse(astral < latin) - self.assertFalse(astral < bmp2) - self.assertTrue(astral < astral2) - self.assertTrue(astral >= ascii) - self.assertTrue(astral >= latin) - self.assertTrue(astral >= bmp2) - self.assertFalse(astral >= astral2) - @support.cpython_only def test_pep393_utf8_caching_bug(self): # Issue #25709: Problem with string concatenation and utf-8 cache @@ -2749,10 +2756,6 @@ # Check that the second call returns the same result self.assertEqual(getargs_s_hash(s), chr(k).encode() * (i + 1)) - def test_free_after_iterating(self): - support.check_free_after_iterating(self, iter, str) - support.check_free_after_iterating(self, reversed, str) - def test_invalid_sequences(self): for letter in string.ascii_letters + "89": # 0-7 are octal escapes if letter in "abfnrtuvxNU": -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mjk1?= =?utf-8?q?=3A_Fixed_the_documentation_and_added_tests_for_PyUnicode=5FAsU?= =?utf-8?b?Q1M0KCku?= Message-ID: <20161002183122.20991.59362.A187D0CF@psf.io> https://hg.python.org/cpython/rev/ac838bf5499d changeset: 104255:ac838bf5499d branch: 3.5 parent: 104252:6dc423b2d929 user: Serhiy Storchaka date: Sun Oct 02 21:29:26 2016 +0300 summary: Issue #28295: Fixed the documentation and added tests for PyUnicode_AsUCS4(). Original patch by Xiang Zhang. files: Doc/c-api/unicode.rst | 2 +- Include/unicodeobject.h | 2 +- Lib/test/test_unicode.py | 17 ++++++++++++++ Modules/_testcapimodule.c | 31 +++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 2 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 @@ -641,7 +641,7 @@ Copy the string *u* into a UCS4 buffer, including a null character, if *copy_null* is set. Returns *NULL* and sets an exception on error (in - particular, a :exc:`ValueError` if *buflen* is smaller than the length of + particular, a :exc:`SystemError` if *buflen* is smaller than the length of *u*). *buffer* is returned on success. .. versionadded:: 3.3 diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -749,7 +749,7 @@ #endif /* Copy the string into a UCS4 buffer including the null character if copy_null - is set. Return NULL and raise an exception on error. Raise a ValueError if + is set. Return NULL and raise an exception on error. Raise a SystemError if the buffer is smaller than the string. Return buffer on success. buflen is the length of the buffer in (Py_UCS4) characters. */ 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 @@ -2687,6 +2687,23 @@ self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') + # Test PyUnicode_AsUCS4() + @support.cpython_only + def test_asucs4(self): + from _testcapi import unicode_asucs4 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', + 'a\ud800b\udfffc', '\ud834\udd1e']: + l = len(s) + self.assertEqual(unicode_asucs4(s, l, 1), s+'\0') + self.assertEqual(unicode_asucs4(s, l, 0), s+'\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 1), s+'\0\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 0), s+'\0\uffff') + self.assertRaises(SystemError, unicode_asucs4, s, l-1, 1) + self.assertRaises(SystemError, unicode_asucs4, s, l-2, 0) + s = '\0'.join([s, s]) + self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') + self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1830,6 +1830,36 @@ } static PyObject * +unicode_asucs4(PyObject *self, PyObject *args) +{ + PyObject *unicode, *result; + Py_UCS4 *buffer; + int copy_null; + Py_ssize_t str_len, buf_len; + + if (!PyArg_ParseTuple(args, "Unp:unicode_asucs4", &unicode, &str_len, ©_null)) { + return NULL; + } + + buf_len = str_len + 1; + buffer = PyMem_NEW(Py_UCS4, buf_len); + if (buffer == NULL) { + return PyErr_NoMemory(); + } + memset(buffer, 0, sizeof(Py_UCS4)*buf_len); + buffer[str_len] = 0xffffU; + + if (!PyUnicode_AsUCS4(unicode, buffer, buf_len, copy_null)) { + PyMem_FREE(buffer); + return NULL; + } + + result = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, buf_len); + PyMem_FREE(buffer); + return result; +} + +static PyObject * unicode_encodedecimal(PyObject *self, PyObject *args) { Py_UNICODE *unicode; @@ -3884,6 +3914,7 @@ {"test_widechar", (PyCFunction)test_widechar, METH_NOARGS}, {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, {"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS}, + {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, {"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS}, {"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS}, {"unicode_legacy_string", unicode_legacy_string, METH_VARARGS}, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:23 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328295=3A_Fixed_the_documentation_and_added_tests_for_?= =?utf-8?q?PyUnicode=5FAsUCS4=28=29=2E?= Message-ID: <20161002183123.15383.11646.D571346D@psf.io> https://hg.python.org/cpython/rev/3efeafc6517a changeset: 104256:3efeafc6517a branch: 3.6 parent: 104253:05788a9a0b88 parent: 104255:ac838bf5499d user: Serhiy Storchaka date: Sun Oct 02 21:30:35 2016 +0300 summary: Issue #28295: Fixed the documentation and added tests for PyUnicode_AsUCS4(). Original patch by Xiang Zhang. files: Doc/c-api/unicode.rst | 2 +- Include/unicodeobject.h | 2 +- Lib/test/test_unicode.py | 17 ++++++++++++++ Modules/_testcapimodule.c | 31 +++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 2 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 @@ -635,7 +635,7 @@ Copy the string *u* into a UCS4 buffer, including a null character, if *copy_null* is set. Returns *NULL* and sets an exception on error (in - particular, a :exc:`ValueError` if *buflen* is smaller than the length of + particular, a :exc:`SystemError` if *buflen* is smaller than the length of *u*). *buffer* is returned on success. .. versionadded:: 3.3 diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -733,7 +733,7 @@ #endif /* Copy the string into a UCS4 buffer including the null character if copy_null - is set. Return NULL and raise an exception on error. Raise a ValueError if + is set. Return NULL and raise an exception on error. Raise a SystemError if the buffer is smaller than the string. Return buffer on success. buflen is the length of the buffer in (Py_UCS4) characters. */ 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 @@ -2711,6 +2711,23 @@ self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') + # Test PyUnicode_AsUCS4() + @support.cpython_only + def test_asucs4(self): + from _testcapi import unicode_asucs4 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', + 'a\ud800b\udfffc', '\ud834\udd1e']: + l = len(s) + self.assertEqual(unicode_asucs4(s, l, 1), s+'\0') + self.assertEqual(unicode_asucs4(s, l, 0), s+'\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 1), s+'\0\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 0), s+'\0\uffff') + self.assertRaises(SystemError, unicode_asucs4, s, l-1, 1) + self.assertRaises(SystemError, unicode_asucs4, s, l-2, 0) + s = '\0'.join([s, s]) + self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') + self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1829,6 +1829,36 @@ } static PyObject * +unicode_asucs4(PyObject *self, PyObject *args) +{ + PyObject *unicode, *result; + Py_UCS4 *buffer; + int copy_null; + Py_ssize_t str_len, buf_len; + + if (!PyArg_ParseTuple(args, "Unp:unicode_asucs4", &unicode, &str_len, ©_null)) { + return NULL; + } + + buf_len = str_len + 1; + buffer = PyMem_NEW(Py_UCS4, buf_len); + if (buffer == NULL) { + return PyErr_NoMemory(); + } + memset(buffer, 0, sizeof(Py_UCS4)*buf_len); + buffer[str_len] = 0xffffU; + + if (!PyUnicode_AsUCS4(unicode, buffer, buf_len, copy_null)) { + PyMem_FREE(buffer); + return NULL; + } + + result = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, buf_len); + PyMem_FREE(buffer); + return result; +} + +static PyObject * unicode_encodedecimal(PyObject *self, PyObject *args) { Py_UNICODE *unicode; @@ -4030,6 +4060,7 @@ {"test_widechar", (PyCFunction)test_widechar, METH_NOARGS}, {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, {"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS}, + {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, {"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS}, {"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS}, {"unicode_legacy_string", unicode_legacy_string, METH_VARARGS}, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 14:31:23 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 18:31:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328295=3A_Fixed_the_documentation_and_added_test?= =?utf-8?q?s_for_PyUnicode=5FAsUCS4=28=29=2E?= Message-ID: <20161002183123.85635.74145.BD3ABBB4@psf.io> https://hg.python.org/cpython/rev/94fb4c4f58dd changeset: 104257:94fb4c4f58dd parent: 104254:343b888a3471 parent: 104256:3efeafc6517a user: Serhiy Storchaka date: Sun Oct 02 21:30:59 2016 +0300 summary: Issue #28295: Fixed the documentation and added tests for PyUnicode_AsUCS4(). Original patch by Xiang Zhang. files: Doc/c-api/unicode.rst | 2 +- Include/unicodeobject.h | 2 +- Lib/test/test_unicode.py | 17 ++++++++++++++ Modules/_testcapimodule.c | 31 +++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 2 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 @@ -635,7 +635,7 @@ Copy the string *u* into a UCS4 buffer, including a null character, if *copy_null* is set. Returns *NULL* and sets an exception on error (in - particular, a :exc:`ValueError` if *buflen* is smaller than the length of + particular, a :exc:`SystemError` if *buflen* is smaller than the length of *u*). *buffer* is returned on success. .. versionadded:: 3.3 diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -733,7 +733,7 @@ #endif /* Copy the string into a UCS4 buffer including the null character if copy_null - is set. Return NULL and raise an exception on error. Raise a ValueError if + is set. Return NULL and raise an exception on error. Raise a SystemError if the buffer is smaller than the string. Return buffer on success. buflen is the length of the buffer in (Py_UCS4) characters. */ 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 @@ -2711,6 +2711,23 @@ self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') + # Test PyUnicode_AsUCS4() + @support.cpython_only + def test_asucs4(self): + from _testcapi import unicode_asucs4 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', + 'a\ud800b\udfffc', '\ud834\udd1e']: + l = len(s) + self.assertEqual(unicode_asucs4(s, l, 1), s+'\0') + self.assertEqual(unicode_asucs4(s, l, 0), s+'\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 1), s+'\0\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 0), s+'\0\uffff') + self.assertRaises(SystemError, unicode_asucs4, s, l-1, 1) + self.assertRaises(SystemError, unicode_asucs4, s, l-2, 0) + s = '\0'.join([s, s]) + self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') + self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1829,6 +1829,36 @@ } static PyObject * +unicode_asucs4(PyObject *self, PyObject *args) +{ + PyObject *unicode, *result; + Py_UCS4 *buffer; + int copy_null; + Py_ssize_t str_len, buf_len; + + if (!PyArg_ParseTuple(args, "Unp:unicode_asucs4", &unicode, &str_len, ©_null)) { + return NULL; + } + + buf_len = str_len + 1; + buffer = PyMem_NEW(Py_UCS4, buf_len); + if (buffer == NULL) { + return PyErr_NoMemory(); + } + memset(buffer, 0, sizeof(Py_UCS4)*buf_len); + buffer[str_len] = 0xffffU; + + if (!PyUnicode_AsUCS4(unicode, buffer, buf_len, copy_null)) { + PyMem_FREE(buffer); + return NULL; + } + + result = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, buf_len); + PyMem_FREE(buffer); + return result; +} + +static PyObject * unicode_encodedecimal(PyObject *self, PyObject *args) { Py_UNICODE *unicode; @@ -4030,6 +4060,7 @@ {"test_widechar", (PyCFunction)test_widechar, METH_NOARGS}, {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, {"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS}, + {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, {"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS}, {"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS}, {"unicode_legacy_string", unicode_legacy_string, METH_VARARGS}, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 15:00:36 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 19:00:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogdGVzdF9pbnZhbGlk?= =?utf-8?q?=5Fsequences_seems_don=27t_have_to_stay_in_CAPITest=2E?= Message-ID: <20161002190028.15292.74748.07633CD3@psf.io> https://hg.python.org/cpython/rev/0d948a46c59a changeset: 104258:0d948a46c59a branch: 3.6 parent: 104256:3efeafc6517a user: Serhiy Storchaka date: Sun Oct 02 21:59:44 2016 +0300 summary: test_invalid_sequences seems don't have to stay in CAPITest. Reported by Xiang Zhang. files: Lib/test/test_unicode.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) 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 @@ -2413,6 +2413,13 @@ support.check_free_after_iterating(self, iter, str) support.check_free_after_iterating(self, reversed, str) + def test_invalid_sequences(self): + for letter in string.ascii_letters + "89": # 0-7 are octal escapes + if letter in "abfnrtuvxNU": + continue + with self.assertWarns(DeprecationWarning): + eval(r"'\%s'" % letter) + class CAPITest(unittest.TestCase): @@ -2773,13 +2780,6 @@ # Check that the second call returns the same result self.assertEqual(getargs_s_hash(s), chr(k).encode() * (i + 1)) - def test_invalid_sequences(self): - for letter in string.ascii_letters + "89": # 0-7 are octal escapes - if letter in "abfnrtuvxNU": - continue - with self.assertWarns(DeprecationWarning): - eval(r"'\%s'" % letter) - class StringModuleTest(unittest.TestCase): def test_formatter_parser(self): def parse(format): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 2 15:00:36 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Oct 2016 19:00:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_test=5Finvalid=5Fsequences_seems_don=27t_have_to_stay_in?= =?utf-8?q?_CAPITest=2E?= Message-ID: <20161002190028.17419.61506.10F39EBA@psf.io> https://hg.python.org/cpython/rev/36b052adf5a7 changeset: 104259:36b052adf5a7 parent: 104257:94fb4c4f58dd parent: 104258:0d948a46c59a user: Serhiy Storchaka date: Sun Oct 02 22:00:05 2016 +0300 summary: test_invalid_sequences seems don't have to stay in CAPITest. Reported by Xiang Zhang. files: Lib/test/test_unicode.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) 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 @@ -2413,6 +2413,13 @@ support.check_free_after_iterating(self, iter, str) support.check_free_after_iterating(self, reversed, str) + def test_invalid_sequences(self): + for letter in string.ascii_letters + "89": # 0-7 are octal escapes + if letter in "abfnrtuvxNU": + continue + with self.assertWarns(DeprecationWarning): + eval(r"'\%s'" % letter) + class CAPITest(unittest.TestCase): @@ -2773,13 +2780,6 @@ # Check that the second call returns the same result self.assertEqual(getargs_s_hash(s), chr(k).encode() * (i + 1)) - def test_invalid_sequences(self): - for letter in string.ascii_letters + "89": # 0-7 are octal escapes - if letter in "abfnrtuvxNU": - continue - with self.assertWarns(DeprecationWarning): - eval(r"'\%s'" % letter) - class StringModuleTest(unittest.TestCase): def test_formatter_parser(self): def parse(format): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 11:42:25 2016 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 03 Oct 2016 15:42:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_More_updates_from_upstream_typing=2Epy_=283=2E5-=3E3=2E6=29?= Message-ID: <20161003154224.15166.38670.90670A63@psf.io> https://hg.python.org/cpython/rev/0e0189b47291 changeset: 104261:0e0189b47291 branch: 3.6 parent: 104258:0d948a46c59a parent: 104260:b24d0f274623 user: Guido van Rossum date: Mon Oct 03 08:41:37 2016 -0700 summary: More updates from upstream typing.py (3.5->3.6) files: Lib/test/test_typing.py | 67 ++++++++++------- Lib/typing.py | 105 ++++++++++++++++++--------- 2 files changed, 108 insertions(+), 64 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -202,10 +202,13 @@ def test_union_any(self): u = Union[Any] self.assertEqual(u, Any) - u = Union[int, Any] - self.assertEqual(u, Any) - u = Union[Any, int] - self.assertEqual(u, Any) + u1 = Union[int, Any] + u2 = Union[Any, int] + u3 = Union[Any, object] + self.assertEqual(u1, u2) + self.assertNotEqual(u1, Any) + self.assertNotEqual(u2, Any) + self.assertNotEqual(u3, Any) def test_union_object(self): u = Union[object] @@ -215,12 +218,6 @@ u = Union[object, int] self.assertEqual(u, object) - def test_union_any_object(self): - u = Union[object, Any] - self.assertEqual(u, Any) - u = Union[Any, object] - self.assertEqual(u, Any) - def test_unordered(self): u1 = Union[int, float] u2 = Union[float, int] @@ -600,8 +597,8 @@ self.assertNotIsInstance({}, MyMapping) self.assertNotIsSubclass(dict, MyMapping) - def test_multiple_abc_bases(self): - class MM1(MutableMapping[str, str], collections_abc.MutableMapping): + def test_abc_bases(self): + class MM(MutableMapping[str, str]): def __getitem__(self, k): return None def __setitem__(self, k, v): @@ -612,24 +609,20 @@ return iter(()) def __len__(self): return 0 - class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): + # this should just work + MM().update() + self.assertIsInstance(MM(), collections_abc.MutableMapping) + self.assertIsInstance(MM(), MutableMapping) + self.assertNotIsInstance(MM(), List) + self.assertNotIsInstance({}, MM) + + def test_multiple_bases(self): + class MM1(MutableMapping[str, str], collections_abc.MutableMapping): + pass + with self.assertRaises(TypeError): + # consistent MRO not possible + class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - # these two should just work - MM1().update() - MM2().update() - self.assertIsInstance(MM1(), collections_abc.MutableMapping) - self.assertIsInstance(MM1(), MutableMapping) - self.assertIsInstance(MM2(), collections_abc.MutableMapping) - self.assertIsInstance(MM2(), MutableMapping) def test_pickle(self): global C # pickle wants to reference the class by name @@ -1380,12 +1373,28 @@ MMA() class MMC(MMA): + def __getitem__(self, k): + return None + def __setitem__(self, k, v): + pass + def __delitem__(self, k): + pass + def __iter__(self): + return iter(()) def __len__(self): return 0 self.assertEqual(len(MMC()), 0) class MMB(typing.MutableMapping[KT, VT]): + def __getitem__(self, k): + return None + def __setitem__(self, k, v): + pass + def __delitem__(self, k): + pass + def __iter__(self): + return iter(()) def __len__(self): return 0 diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -143,7 +143,6 @@ __slots__ = () - def __init__(self, *args, **kwds): pass @@ -158,7 +157,7 @@ isinstance(args[1], tuple)): # Close enough. raise TypeError("Cannot subclass %r" % cls) - return object.__new__(cls) + return super().__new__(cls) # Things that are not classes also need these. def _eval_type(self, globalns, localns): @@ -177,7 +176,11 @@ class _FinalTypingBase(_TypingBase, _root=True): - """Mix-in class to prevent instantiation.""" + """Mix-in class to prevent instantiation. + + Prevents instantiation unless _root=True is given in class call. + It is used to create pseudo-singleton instances Any, Union, Tuple, etc. + """ __slots__ = () @@ -273,7 +276,7 @@ assert isinstance(name, str), repr(name) assert isinstance(impl_type, type), repr(impl_type) assert not isinstance(impl_type, TypingMeta), repr(impl_type) - assert isinstance(type_var, (type, _TypingBase)) + assert isinstance(type_var, (type, _TypingBase)), repr(type_var) self.name = name self.type_var = type_var self.impl_type = impl_type @@ -375,9 +378,13 @@ class _Any(_FinalTypingBase, _root=True): """Special type indicating an unconstrained type. - - Any object is an instance of Any. - - Any class is a subclass of Any. - - As a special case, Any and object are subclasses of each other. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + or class checks. """ __slots__ = () @@ -502,7 +509,7 @@ try: return cached(*args, **kwds) except TypeError: - pass # Do not duplicate real errors. + pass # All real errors (not unhashable args) are raised below. return func(*args, **kwds) return inner @@ -542,16 +549,10 @@ Union[Manager, int, Employee] == Union[int, Employee] Union[Employee, Manager] == Employee - - Corollary: if Any is present it is the sole survivor, e.g.:: - - Union[int, Any] == Any - - Similar for object:: Union[int, object] == object - - To cut a tie: Union[object, Any] == Union[Any, object] == Any. - - You cannot subclass or instantiate a union. - You cannot write Union[X][Y] (what would it mean?). @@ -589,14 +590,11 @@ assert not all_params, all_params # Weed out subclasses. # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If Any or object is present it will be the sole survivor. - # If both Any and object are present, Any wins. - # Never discard type variables, except against Any. + # If object is present it will be sole survivor among proper classes. + # Never discard type variables. # (In particular, Union[str, AnyStr] != AnyStr.) all_params = set(params) for t1 in params: - if t1 is Any: - return Any if not isinstance(t1, type): continue if any(isinstance(t2, type) and issubclass(t1, t2) @@ -662,7 +660,7 @@ class _Optional(_FinalTypingBase, _root=True): """Optional type. - Optional[X] is equivalent to Union[X, type(None)]. + Optional[X] is equivalent to Union[X, None]. """ __slots__ = () @@ -894,11 +892,55 @@ return next_in_mro +def _valid_for_check(cls): + if cls is Generic: + raise TypeError("Class %r cannot be used with class " + "or instance checks" % cls) + if (cls.__origin__ is not None and + sys._getframe(3).f_globals['__name__'] not in ['abc', 'functools']): + raise TypeError("Parameterized generics cannot be used with class " + "or instance checks") + + +def _make_subclasshook(cls): + """Construct a __subclasshook__ callable that incorporates + the associated __extra__ class in subclass checks performed + against cls. + """ + if isinstance(cls.__extra__, abc.ABCMeta): + # The logic mirrors that of ABCMeta.__subclasscheck__. + # Registered classes need not be checked here because + # cls and its extra share the same _abc_registry. + def __extrahook__(subclass): + _valid_for_check(cls) + res = cls.__extra__.__subclasshook__(subclass) + if res is not NotImplemented: + return res + if cls.__extra__ in subclass.__mro__: + return True + for scls in cls.__extra__.__subclasses__(): + if isinstance(scls, GenericMeta): + continue + if issubclass(subclass, scls): + return True + return NotImplemented + else: + # For non-ABC extras we'll just call issubclass(). + def __extrahook__(subclass): + _valid_for_check(cls) + if cls.__extra__ and issubclass(subclass, cls.__extra__): + return True + return NotImplemented + return __extrahook__ + + class GenericMeta(TypingMeta, abc.ABCMeta): """Metaclass for generic types.""" def __new__(cls, name, bases, namespace, tvars=None, args=None, origin=None, extra=None): + if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: + bases = (extra,) + bases self = super().__new__(cls, name, bases, namespace, _root=True) if tvars is not None: @@ -947,6 +989,13 @@ self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). self.__next_in_mro__ = _next_in_mro(self) + + # This allows unparameterized generic collections to be used + # with issubclass() and isinstance() in the same way as their + # collections.abc counterparts (e.g., isinstance([], Iterable)). + self.__subclasshook__ = _make_subclasshook(self) + if isinstance(extra, abc.ABCMeta): + self._abc_registry = extra._abc_registry return self def _get_type_vars(self, tvars): @@ -1032,21 +1081,7 @@ # latter, we must extend __instancecheck__ too. For simplicity # we just skip the cache check -- instance checks for generic # classes are supposed to be rare anyways. - return self.__subclasscheck__(instance.__class__) - - def __subclasscheck__(self, cls): - if self is Generic: - raise TypeError("Class %r cannot be used with class " - "or instance checks" % self) - if (self.__origin__ is not None and - sys._getframe(1).f_globals['__name__'] != 'abc'): - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - if super().__subclasscheck__(cls): - return True - if self.__extra__ is not None: - return issubclass(cls, self.__extra__) - return False + return issubclass(instance.__class__, self) # Prevent checks for Generic to crash when defining Generic. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 11:42:25 2016 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 03 Oct 2016 15:42:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_More_updates_f?= =?utf-8?q?rom_upstream_typing=2Epy?= Message-ID: <20161003154224.94878.73993.6D224CA6@psf.io> https://hg.python.org/cpython/rev/b24d0f274623 changeset: 104260:b24d0f274623 branch: 3.5 parent: 104255:ac838bf5499d user: Guido van Rossum date: Mon Oct 03 08:40:50 2016 -0700 summary: More updates from upstream typing.py files: Lib/test/test_typing.py | 67 ++++++++++------- Lib/typing.py | 105 ++++++++++++++++++--------- 2 files changed, 108 insertions(+), 64 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -202,10 +202,13 @@ def test_union_any(self): u = Union[Any] self.assertEqual(u, Any) - u = Union[int, Any] - self.assertEqual(u, Any) - u = Union[Any, int] - self.assertEqual(u, Any) + u1 = Union[int, Any] + u2 = Union[Any, int] + u3 = Union[Any, object] + self.assertEqual(u1, u2) + self.assertNotEqual(u1, Any) + self.assertNotEqual(u2, Any) + self.assertNotEqual(u3, Any) def test_union_object(self): u = Union[object] @@ -215,12 +218,6 @@ u = Union[object, int] self.assertEqual(u, object) - def test_union_any_object(self): - u = Union[object, Any] - self.assertEqual(u, Any) - u = Union[Any, object] - self.assertEqual(u, Any) - def test_unordered(self): u1 = Union[int, float] u2 = Union[float, int] @@ -600,8 +597,8 @@ self.assertNotIsInstance({}, MyMapping) self.assertNotIsSubclass(dict, MyMapping) - def test_multiple_abc_bases(self): - class MM1(MutableMapping[str, str], collections_abc.MutableMapping): + def test_abc_bases(self): + class MM(MutableMapping[str, str]): def __getitem__(self, k): return None def __setitem__(self, k, v): @@ -612,24 +609,20 @@ return iter(()) def __len__(self): return 0 - class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): + # this should just work + MM().update() + self.assertIsInstance(MM(), collections_abc.MutableMapping) + self.assertIsInstance(MM(), MutableMapping) + self.assertNotIsInstance(MM(), List) + self.assertNotIsInstance({}, MM) + + def test_multiple_bases(self): + class MM1(MutableMapping[str, str], collections_abc.MutableMapping): + pass + with self.assertRaises(TypeError): + # consistent MRO not possible + class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - # these two should just work - MM1().update() - MM2().update() - self.assertIsInstance(MM1(), collections_abc.MutableMapping) - self.assertIsInstance(MM1(), MutableMapping) - self.assertIsInstance(MM2(), collections_abc.MutableMapping) - self.assertIsInstance(MM2(), MutableMapping) def test_pickle(self): global C # pickle wants to reference the class by name @@ -1380,12 +1373,28 @@ MMA() class MMC(MMA): + def __getitem__(self, k): + return None + def __setitem__(self, k, v): + pass + def __delitem__(self, k): + pass + def __iter__(self): + return iter(()) def __len__(self): return 0 self.assertEqual(len(MMC()), 0) class MMB(typing.MutableMapping[KT, VT]): + def __getitem__(self, k): + return None + def __setitem__(self, k, v): + pass + def __delitem__(self, k): + pass + def __iter__(self): + return iter(()) def __len__(self): return 0 diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -143,7 +143,6 @@ __slots__ = () - def __init__(self, *args, **kwds): pass @@ -158,7 +157,7 @@ isinstance(args[1], tuple)): # Close enough. raise TypeError("Cannot subclass %r" % cls) - return object.__new__(cls) + return super().__new__(cls) # Things that are not classes also need these. def _eval_type(self, globalns, localns): @@ -177,7 +176,11 @@ class _FinalTypingBase(_TypingBase, _root=True): - """Mix-in class to prevent instantiation.""" + """Mix-in class to prevent instantiation. + + Prevents instantiation unless _root=True is given in class call. + It is used to create pseudo-singleton instances Any, Union, Tuple, etc. + """ __slots__ = () @@ -273,7 +276,7 @@ assert isinstance(name, str), repr(name) assert isinstance(impl_type, type), repr(impl_type) assert not isinstance(impl_type, TypingMeta), repr(impl_type) - assert isinstance(type_var, (type, _TypingBase)) + assert isinstance(type_var, (type, _TypingBase)), repr(type_var) self.name = name self.type_var = type_var self.impl_type = impl_type @@ -375,9 +378,13 @@ class _Any(_FinalTypingBase, _root=True): """Special type indicating an unconstrained type. - - Any object is an instance of Any. - - Any class is a subclass of Any. - - As a special case, Any and object are subclasses of each other. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + or class checks. """ __slots__ = () @@ -502,7 +509,7 @@ try: return cached(*args, **kwds) except TypeError: - pass # Do not duplicate real errors. + pass # All real errors (not unhashable args) are raised below. return func(*args, **kwds) return inner @@ -542,16 +549,10 @@ Union[Manager, int, Employee] == Union[int, Employee] Union[Employee, Manager] == Employee - - Corollary: if Any is present it is the sole survivor, e.g.:: - - Union[int, Any] == Any - - Similar for object:: Union[int, object] == object - - To cut a tie: Union[object, Any] == Union[Any, object] == Any. - - You cannot subclass or instantiate a union. - You cannot write Union[X][Y] (what would it mean?). @@ -589,14 +590,11 @@ assert not all_params, all_params # Weed out subclasses. # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If Any or object is present it will be the sole survivor. - # If both Any and object are present, Any wins. - # Never discard type variables, except against Any. + # If object is present it will be sole survivor among proper classes. + # Never discard type variables. # (In particular, Union[str, AnyStr] != AnyStr.) all_params = set(params) for t1 in params: - if t1 is Any: - return Any if not isinstance(t1, type): continue if any(isinstance(t2, type) and issubclass(t1, t2) @@ -662,7 +660,7 @@ class _Optional(_FinalTypingBase, _root=True): """Optional type. - Optional[X] is equivalent to Union[X, type(None)]. + Optional[X] is equivalent to Union[X, None]. """ __slots__ = () @@ -894,11 +892,55 @@ return next_in_mro +def _valid_for_check(cls): + if cls is Generic: + raise TypeError("Class %r cannot be used with class " + "or instance checks" % cls) + if (cls.__origin__ is not None and + sys._getframe(3).f_globals['__name__'] not in ['abc', 'functools']): + raise TypeError("Parameterized generics cannot be used with class " + "or instance checks") + + +def _make_subclasshook(cls): + """Construct a __subclasshook__ callable that incorporates + the associated __extra__ class in subclass checks performed + against cls. + """ + if isinstance(cls.__extra__, abc.ABCMeta): + # The logic mirrors that of ABCMeta.__subclasscheck__. + # Registered classes need not be checked here because + # cls and its extra share the same _abc_registry. + def __extrahook__(subclass): + _valid_for_check(cls) + res = cls.__extra__.__subclasshook__(subclass) + if res is not NotImplemented: + return res + if cls.__extra__ in subclass.__mro__: + return True + for scls in cls.__extra__.__subclasses__(): + if isinstance(scls, GenericMeta): + continue + if issubclass(subclass, scls): + return True + return NotImplemented + else: + # For non-ABC extras we'll just call issubclass(). + def __extrahook__(subclass): + _valid_for_check(cls) + if cls.__extra__ and issubclass(subclass, cls.__extra__): + return True + return NotImplemented + return __extrahook__ + + class GenericMeta(TypingMeta, abc.ABCMeta): """Metaclass for generic types.""" def __new__(cls, name, bases, namespace, tvars=None, args=None, origin=None, extra=None): + if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: + bases = (extra,) + bases self = super().__new__(cls, name, bases, namespace, _root=True) if tvars is not None: @@ -947,6 +989,13 @@ self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). self.__next_in_mro__ = _next_in_mro(self) + + # This allows unparameterized generic collections to be used + # with issubclass() and isinstance() in the same way as their + # collections.abc counterparts (e.g., isinstance([], Iterable)). + self.__subclasshook__ = _make_subclasshook(self) + if isinstance(extra, abc.ABCMeta): + self._abc_registry = extra._abc_registry return self def _get_type_vars(self, tvars): @@ -1032,21 +1081,7 @@ # latter, we must extend __instancecheck__ too. For simplicity # we just skip the cache check -- instance checks for generic # classes are supposed to be rare anyways. - return self.__subclasscheck__(instance.__class__) - - def __subclasscheck__(self, cls): - if self is Generic: - raise TypeError("Class %r cannot be used with class " - "or instance checks" % self) - if (self.__origin__ is not None and - sys._getframe(1).f_globals['__name__'] != 'abc'): - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - if super().__subclasscheck__(cls): - return True - if self.__extra__ is not None: - return issubclass(cls, self.__extra__) - return False + return issubclass(instance.__class__, self) # Prevent checks for Generic to crash when defining Generic. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 11:42:25 2016 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 03 Oct 2016 15:42:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_More_updates_from_upstream_typing=2Epy_=283=2E6-=3E3=2E7?= =?utf-8?q?=29?= Message-ID: <20161003154225.15320.78509.544C7058@psf.io> https://hg.python.org/cpython/rev/7f0d27180b6d changeset: 104262:7f0d27180b6d parent: 104259:36b052adf5a7 parent: 104261:0e0189b47291 user: Guido van Rossum date: Mon Oct 03 08:42:17 2016 -0700 summary: More updates from upstream typing.py (3.6->3.7) files: Lib/test/test_typing.py | 67 ++++++++++------- Lib/typing.py | 105 ++++++++++++++++++--------- 2 files changed, 108 insertions(+), 64 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -202,10 +202,13 @@ def test_union_any(self): u = Union[Any] self.assertEqual(u, Any) - u = Union[int, Any] - self.assertEqual(u, Any) - u = Union[Any, int] - self.assertEqual(u, Any) + u1 = Union[int, Any] + u2 = Union[Any, int] + u3 = Union[Any, object] + self.assertEqual(u1, u2) + self.assertNotEqual(u1, Any) + self.assertNotEqual(u2, Any) + self.assertNotEqual(u3, Any) def test_union_object(self): u = Union[object] @@ -215,12 +218,6 @@ u = Union[object, int] self.assertEqual(u, object) - def test_union_any_object(self): - u = Union[object, Any] - self.assertEqual(u, Any) - u = Union[Any, object] - self.assertEqual(u, Any) - def test_unordered(self): u1 = Union[int, float] u2 = Union[float, int] @@ -600,8 +597,8 @@ self.assertNotIsInstance({}, MyMapping) self.assertNotIsSubclass(dict, MyMapping) - def test_multiple_abc_bases(self): - class MM1(MutableMapping[str, str], collections_abc.MutableMapping): + def test_abc_bases(self): + class MM(MutableMapping[str, str]): def __getitem__(self, k): return None def __setitem__(self, k, v): @@ -612,24 +609,20 @@ return iter(()) def __len__(self): return 0 - class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): + # this should just work + MM().update() + self.assertIsInstance(MM(), collections_abc.MutableMapping) + self.assertIsInstance(MM(), MutableMapping) + self.assertNotIsInstance(MM(), List) + self.assertNotIsInstance({}, MM) + + def test_multiple_bases(self): + class MM1(MutableMapping[str, str], collections_abc.MutableMapping): + pass + with self.assertRaises(TypeError): + # consistent MRO not possible + class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - # these two should just work - MM1().update() - MM2().update() - self.assertIsInstance(MM1(), collections_abc.MutableMapping) - self.assertIsInstance(MM1(), MutableMapping) - self.assertIsInstance(MM2(), collections_abc.MutableMapping) - self.assertIsInstance(MM2(), MutableMapping) def test_pickle(self): global C # pickle wants to reference the class by name @@ -1380,12 +1373,28 @@ MMA() class MMC(MMA): + def __getitem__(self, k): + return None + def __setitem__(self, k, v): + pass + def __delitem__(self, k): + pass + def __iter__(self): + return iter(()) def __len__(self): return 0 self.assertEqual(len(MMC()), 0) class MMB(typing.MutableMapping[KT, VT]): + def __getitem__(self, k): + return None + def __setitem__(self, k, v): + pass + def __delitem__(self, k): + pass + def __iter__(self): + return iter(()) def __len__(self): return 0 diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -143,7 +143,6 @@ __slots__ = () - def __init__(self, *args, **kwds): pass @@ -158,7 +157,7 @@ isinstance(args[1], tuple)): # Close enough. raise TypeError("Cannot subclass %r" % cls) - return object.__new__(cls) + return super().__new__(cls) # Things that are not classes also need these. def _eval_type(self, globalns, localns): @@ -177,7 +176,11 @@ class _FinalTypingBase(_TypingBase, _root=True): - """Mix-in class to prevent instantiation.""" + """Mix-in class to prevent instantiation. + + Prevents instantiation unless _root=True is given in class call. + It is used to create pseudo-singleton instances Any, Union, Tuple, etc. + """ __slots__ = () @@ -273,7 +276,7 @@ assert isinstance(name, str), repr(name) assert isinstance(impl_type, type), repr(impl_type) assert not isinstance(impl_type, TypingMeta), repr(impl_type) - assert isinstance(type_var, (type, _TypingBase)) + assert isinstance(type_var, (type, _TypingBase)), repr(type_var) self.name = name self.type_var = type_var self.impl_type = impl_type @@ -375,9 +378,13 @@ class _Any(_FinalTypingBase, _root=True): """Special type indicating an unconstrained type. - - Any object is an instance of Any. - - Any class is a subclass of Any. - - As a special case, Any and object are subclasses of each other. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + or class checks. """ __slots__ = () @@ -502,7 +509,7 @@ try: return cached(*args, **kwds) except TypeError: - pass # Do not duplicate real errors. + pass # All real errors (not unhashable args) are raised below. return func(*args, **kwds) return inner @@ -542,16 +549,10 @@ Union[Manager, int, Employee] == Union[int, Employee] Union[Employee, Manager] == Employee - - Corollary: if Any is present it is the sole survivor, e.g.:: - - Union[int, Any] == Any - - Similar for object:: Union[int, object] == object - - To cut a tie: Union[object, Any] == Union[Any, object] == Any. - - You cannot subclass or instantiate a union. - You cannot write Union[X][Y] (what would it mean?). @@ -589,14 +590,11 @@ assert not all_params, all_params # Weed out subclasses. # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If Any or object is present it will be the sole survivor. - # If both Any and object are present, Any wins. - # Never discard type variables, except against Any. + # If object is present it will be sole survivor among proper classes. + # Never discard type variables. # (In particular, Union[str, AnyStr] != AnyStr.) all_params = set(params) for t1 in params: - if t1 is Any: - return Any if not isinstance(t1, type): continue if any(isinstance(t2, type) and issubclass(t1, t2) @@ -662,7 +660,7 @@ class _Optional(_FinalTypingBase, _root=True): """Optional type. - Optional[X] is equivalent to Union[X, type(None)]. + Optional[X] is equivalent to Union[X, None]. """ __slots__ = () @@ -894,11 +892,55 @@ return next_in_mro +def _valid_for_check(cls): + if cls is Generic: + raise TypeError("Class %r cannot be used with class " + "or instance checks" % cls) + if (cls.__origin__ is not None and + sys._getframe(3).f_globals['__name__'] not in ['abc', 'functools']): + raise TypeError("Parameterized generics cannot be used with class " + "or instance checks") + + +def _make_subclasshook(cls): + """Construct a __subclasshook__ callable that incorporates + the associated __extra__ class in subclass checks performed + against cls. + """ + if isinstance(cls.__extra__, abc.ABCMeta): + # The logic mirrors that of ABCMeta.__subclasscheck__. + # Registered classes need not be checked here because + # cls and its extra share the same _abc_registry. + def __extrahook__(subclass): + _valid_for_check(cls) + res = cls.__extra__.__subclasshook__(subclass) + if res is not NotImplemented: + return res + if cls.__extra__ in subclass.__mro__: + return True + for scls in cls.__extra__.__subclasses__(): + if isinstance(scls, GenericMeta): + continue + if issubclass(subclass, scls): + return True + return NotImplemented + else: + # For non-ABC extras we'll just call issubclass(). + def __extrahook__(subclass): + _valid_for_check(cls) + if cls.__extra__ and issubclass(subclass, cls.__extra__): + return True + return NotImplemented + return __extrahook__ + + class GenericMeta(TypingMeta, abc.ABCMeta): """Metaclass for generic types.""" def __new__(cls, name, bases, namespace, tvars=None, args=None, origin=None, extra=None): + if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: + bases = (extra,) + bases self = super().__new__(cls, name, bases, namespace, _root=True) if tvars is not None: @@ -947,6 +989,13 @@ self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). self.__next_in_mro__ = _next_in_mro(self) + + # This allows unparameterized generic collections to be used + # with issubclass() and isinstance() in the same way as their + # collections.abc counterparts (e.g., isinstance([], Iterable)). + self.__subclasshook__ = _make_subclasshook(self) + if isinstance(extra, abc.ABCMeta): + self._abc_registry = extra._abc_registry return self def _get_type_vars(self, tvars): @@ -1032,21 +1081,7 @@ # latter, we must extend __instancecheck__ too. For simplicity # we just skip the cache check -- instance checks for generic # classes are supposed to be rare anyways. - return self.__subclasscheck__(instance.__class__) - - def __subclasscheck__(self, cls): - if self is Generic: - raise TypeError("Class %r cannot be used with class " - "or instance checks" % self) - if (self.__origin__ is not None and - sys._getframe(1).f_globals['__name__'] != 'abc'): - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - if super().__subclasscheck__(cls): - return True - if self.__extra__ is not None: - return issubclass(cls, self.__extra__) - return False + return issubclass(instance.__class__, self) # Prevent checks for Generic to crash when defining Generic. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 12:12:53 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 03 Oct 2016 16:12:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328217=3A_Adds_=5Ftestconsole_module_to_test_con?= =?utf-8?q?sole_input=2E?= Message-ID: <20161003161252.85703.71778.18614210@psf.io> https://hg.python.org/cpython/rev/3ec6a610e93e changeset: 104264:3ec6a610e93e parent: 104262:7f0d27180b6d parent: 104263:363888141f41 user: Steve Dower date: Mon Oct 03 09:12:42 2016 -0700 summary: Issue #28217: Adds _testconsole module to test console input. files: Lib/test/test_winconsoleio.py | 70 +++++++- Misc/NEWS | 5 + Modules/_io/_iomodule.h | 3 +- Modules/_io/winconsoleio.c | 54 ++++- PC/_testconsole.c | 131 +++++++++++++++ PC/clinic/_testconsole.c.h | 82 +++++++++ PCbuild/_testconsole.vcxproj | 83 +++++++++ PCbuild/_testconsole.vcxproj.filters | 22 ++ PCbuild/pcbuild.proj | 2 +- PCbuild/pcbuild.sln | 18 ++ Tools/msi/test/test_files.wxs | 12 + 11 files changed, 461 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py --- a/Lib/test/test_winconsoleio.py +++ b/Lib/test/test_winconsoleio.py @@ -1,12 +1,4 @@ '''Tests for WindowsConsoleIO - -Unfortunately, most testing requires interactive use, since we have no -API to read back from a real console, and this class is only for use -with real consoles. - -Instead, we validate that basic functionality such as opening, closing -and in particular fileno() work, but are forced to leave real testing -to real people with real keyborads. ''' import io @@ -16,6 +8,8 @@ if sys.platform != 'win32': raise unittest.SkipTest("test only relevant on win32") +from _testconsole import write_input + ConIO = io._WindowsConsoleIO class WindowsConsoleIOTests(unittest.TestCase): @@ -83,5 +77,65 @@ f.close() f.close() + def assertStdinRoundTrip(self, text): + stdin = open('CONIN$', 'r') + old_stdin = sys.stdin + try: + sys.stdin = stdin + write_input( + stdin.buffer.raw, + (text + '\r\n').encode('utf-16-le', 'surrogatepass') + ) + actual = input() + finally: + sys.stdin = old_stdin + self.assertEqual(actual, text) + + def test_input(self): + # ASCII + self.assertStdinRoundTrip('abc123') + # Non-ASCII + self.assertStdinRoundTrip('??????') + # Combining characters + self.assertStdinRoundTrip('A?B ??AA?') + # Non-BMP + self.assertStdinRoundTrip('\U00100000\U0010ffff\U0010fffd') + + def test_partial_reads(self): + # Test that reading less than 1 full character works when stdin + # contains multibyte UTF-8 sequences + source = '??????\r\n'.encode('utf-16-le') + expected = '??????\r\n'.encode('utf-8') + for read_count in range(1, 16): + stdin = open('CONIN$', 'rb', buffering=0) + write_input(stdin, source) + + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b + + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) + stdin.close() + + def test_partial_surrogate_reads(self): + # Test that reading less than 1 full character works when stdin + # contains surrogate pairs that cannot be decoded to UTF-8 without + # reading an extra character. + source = '\U00101FFF\U00101001\r\n'.encode('utf-16-le') + expected = '\U00101FFF\U00101001\r\n'.encode('utf-8') + for read_count in range(1, 16): + stdin = open('CONIN$', 'rb', buffering=0) + write_input(stdin, source) + + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b + + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) + stdin.close() + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -224,6 +224,11 @@ - Issue #28102: The zipfile module CLI now prints usage to stderr. Patch by Stephen J. Turnbull. +Tests +----- + +- Issue #28217: Adds _testconsole module to test console input. + What's New in Python 3.6.0 beta 1 ================================= diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -22,7 +22,8 @@ #ifndef Py_LIMITED_API #ifdef MS_WINDOWS extern PyTypeObject PyWindowsConsoleIO_Type; -#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type)) +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type; +#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), (PyTypeObject*)_PyWindowsConsoleIO_Type)) #endif /* MS_WINDOWS */ #endif /* Py_LIMITED_API */ diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -39,6 +39,11 @@ /* BUFMAX determines how many bytes can be read in one go. */ #define BUFMAX (32*1024*1024) +/* SMALLBUF determines how many utf-8 characters will be + buffered within the stream, in order to support reads + of less than one character */ +#define SMALLBUF 4 + char _get_console_type(HANDLE handle) { DWORD mode, peek_count; @@ -125,7 +130,8 @@ unsigned int blksize; PyObject *weakreflist; PyObject *dict; - char buf[4]; + char buf[SMALLBUF]; + wchar_t wbuf; } winconsoleio; PyTypeObject PyWindowsConsoleIO_Type; @@ -500,11 +506,11 @@ static DWORD _buflen(winconsoleio *self) { - for (DWORD i = 0; i < 4; ++i) { + for (DWORD i = 0; i < SMALLBUF; ++i) { if (!self->buf[i]) return i; } - return 4; + return SMALLBUF; } static DWORD @@ -513,12 +519,10 @@ DWORD n = 0; while (self->buf[0] && len--) { - n += 1; - buf[0] = self->buf[0]; - self->buf[0] = self->buf[1]; - self->buf[1] = self->buf[2]; - self->buf[2] = self->buf[3]; - self->buf[3] = 0; + buf[n++] = self->buf[0]; + for (int i = 1; i < SMALLBUF; ++i) + self->buf[i - 1] = self->buf[i]; + self->buf[SMALLBUF - 1] = 0; } return n; @@ -531,10 +535,13 @@ wchar_t *buf = (wchar_t*)PyMem_Malloc(maxlen * sizeof(wchar_t)); if (!buf) goto error; + *readlen = 0; + //DebugBreak(); Py_BEGIN_ALLOW_THREADS - for (DWORD off = 0; off < maxlen; off += BUFSIZ) { + DWORD off = 0; + while (off < maxlen) { DWORD n, len = min(maxlen - off, BUFSIZ); SetLastError(0); BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); @@ -550,7 +557,7 @@ err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) - == WAIT_OBJECT_0) { + == WAIT_OBJECT_0) { ResetEvent(hInterruptEvent); Py_BLOCK_THREADS sig = PyErr_CheckSignals(); @@ -568,7 +575,30 @@ /* If the buffer ended with a newline, break out */ if (buf[*readlen - 1] == '\n') break; + /* If the buffer ends with a high surrogate, expand the + buffer and read an extra character. */ + WORD char_type; + if (off + BUFSIZ >= maxlen && + GetStringTypeW(CT_CTYPE3, &buf[*readlen - 1], 1, &char_type) && + char_type == C3_HIGHSURROGATE) { + wchar_t *newbuf; + maxlen += 1; + Py_BLOCK_THREADS + newbuf = (wchar_t*)PyMem_Realloc(buf, maxlen * sizeof(wchar_t)); + Py_UNBLOCK_THREADS + if (!newbuf) { + sig = -1; + break; + } + buf = newbuf; + /* Only advance by n and not BUFSIZ in this case */ + off += n; + continue; + } + + off += BUFSIZ; } + Py_END_ALLOW_THREADS if (sig) @@ -1110,4 +1140,6 @@ 0, /* tp_finalize */ }; +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type = (PyObject*)&PyWindowsConsoleIO_Type; + #endif /* MS_WINDOWS */ diff --git a/PC/_testconsole.c b/PC/_testconsole.c new file mode 100644 --- /dev/null +++ b/PC/_testconsole.c @@ -0,0 +1,131 @@ + +/* Testing module for multi-phase initialization of extension modules (PEP 489) + */ + +#include "Python.h" + +#ifdef MS_WINDOWS + +#include "..\modules\_io\_iomodule.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + + /* The full definition is in iomodule. We reproduce + enough here to get the handle, which is all we want. */ +typedef struct { + PyObject_HEAD + HANDLE handle; +} winconsoleio; + + +static int execfunc(PyObject *m) +{ + return 0; +} + +PyModuleDef_Slot testconsole_slots[] = { + {Py_mod_exec, execfunc}, + {0, NULL}, +}; + +/*[clinic input] +module _testconsole + +_testconsole.write_input + file: object + s: PyBytesObject + +Writes UTF-16-LE encoded bytes to the console as if typed by a user. +[clinic start generated code]*/ + +static PyObject * +_testconsole_write_input_impl(PyObject *module, PyObject *file, + PyBytesObject *s) +/*[clinic end generated code: output=48f9563db34aedb3 input=4c774f2d05770bc6]*/ +{ + INPUT_RECORD *rec = NULL; + + if (!PyWindowsConsoleIO_Check(file)) { + PyErr_SetString(PyExc_TypeError, "expected raw console object"); + return NULL; + } + + const wchar_t *p = (const wchar_t *)PyBytes_AS_STRING(s); + DWORD size = (DWORD)PyBytes_GET_SIZE(s) / sizeof(wchar_t); + + rec = (INPUT_RECORD*)PyMem_Malloc(sizeof(INPUT_RECORD) * size); + if (!rec) + goto error; + memset(rec, 0, sizeof(INPUT_RECORD) * size); + + INPUT_RECORD *prec = rec; + for (DWORD i = 0; i < size; ++i, ++p, ++prec) { + prec->EventType = KEY_EVENT; + prec->Event.KeyEvent.bKeyDown = TRUE; + prec->Event.KeyEvent.wRepeatCount = 10; + prec->Event.KeyEvent.uChar.UnicodeChar = *p; + } + + HANDLE hInput = ((winconsoleio*)file)->handle; + DWORD total = 0; + while (total < size) { + DWORD wrote; + if (!WriteConsoleInputW(hInput, &rec[total], (size - total), &wrote)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + total += wrote; + } + + PyMem_Free((void*)rec); + + Py_RETURN_NONE; +error: + if (rec) + PyMem_Free((void*)rec); + return NULL; +} + +/*[clinic input] +_testconsole.read_output + file: object + +Reads a str from the console as written to stdout. +[clinic start generated code]*/ + +static PyObject * +_testconsole_read_output_impl(PyObject *module, PyObject *file) +/*[clinic end generated code: output=876310d81a73e6d2 input=b3521f64b1b558e3]*/ +{ + Py_RETURN_NONE; +} + +#include "clinic\_testconsole.c.h" + +PyMethodDef testconsole_methods[] = { + _TESTCONSOLE_WRITE_INPUT_METHODDEF + _TESTCONSOLE_READ_OUTPUT_METHODDEF + {NULL, NULL} +}; + +static PyModuleDef testconsole_def = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_testconsole", /* m_name */ + PyDoc_STR("Test module for the Windows console"), /* m_doc */ + 0, /* m_size */ + testconsole_methods, /* m_methods */ + testconsole_slots, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyMODINIT_FUNC +PyInit__testconsole(PyObject *spec) +{ + return PyModuleDef_Init(&testconsole_def); +} + +#endif /* MS_WINDOWS */ diff --git a/PC/clinic/_testconsole.c.h b/PC/clinic/_testconsole.c.h new file mode 100644 --- /dev/null +++ b/PC/clinic/_testconsole.c.h @@ -0,0 +1,82 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_testconsole_write_input__doc__, +"write_input($module, /, file, s)\n" +"--\n" +"\n" +"Writes UTF-16-LE encoded bytes to the console as if typed by a user."); + +#define _TESTCONSOLE_WRITE_INPUT_METHODDEF \ + {"write_input", (PyCFunction)_testconsole_write_input, METH_FASTCALL, _testconsole_write_input__doc__}, + +static PyObject * +_testconsole_write_input_impl(PyObject *module, PyObject *file, + PyBytesObject *s); + +static PyObject * +_testconsole_write_input(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"file", "s", NULL}; + static _PyArg_Parser _parser = {"OS:write_input", _keywords, 0}; + PyObject *file; + PyBytesObject *s; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &file, &s)) { + goto exit; + } + return_value = _testconsole_write_input_impl(module, file, s); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_testconsole_read_output__doc__, +"read_output($module, /, file)\n" +"--\n" +"\n" +"Reads a str from the console as written to stdout."); + +#define _TESTCONSOLE_READ_OUTPUT_METHODDEF \ + {"read_output", (PyCFunction)_testconsole_read_output, METH_FASTCALL, _testconsole_read_output__doc__}, + +static PyObject * +_testconsole_read_output_impl(PyObject *module, PyObject *file); + +static PyObject * +_testconsole_read_output(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"file", NULL}; + static _PyArg_Parser _parser = {"O:read_output", _keywords, 0}; + PyObject *file; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &file)) { + goto exit; + } + return_value = _testconsole_read_output_impl(module, file); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#ifndef _TESTCONSOLE_WRITE_INPUT_METHODDEF + #define _TESTCONSOLE_WRITE_INPUT_METHODDEF +#endif /* !defined(_TESTCONSOLE_WRITE_INPUT_METHODDEF) */ + +#ifndef _TESTCONSOLE_READ_OUTPUT_METHODDEF + #define _TESTCONSOLE_READ_OUTPUT_METHODDEF +#endif /* !defined(_TESTCONSOLE_READ_OUTPUT_METHODDEF) */ +/*[clinic end generated code: output=3a8dc0c421807c41 input=a9049054013a1b77]*/ diff --git a/PCbuild/_testconsole.vcxproj b/PCbuild/_testconsole.vcxproj new file mode 100644 --- /dev/null +++ b/PCbuild/_testconsole.vcxproj @@ -0,0 +1,83 @@ +? + + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + Win32 + + + Release + x64 + + + + {B244E787-C445-441C-BDF4-5A4F1A3A1E51} + Win32Proj + _testconsole + false + + + + + DynamicLibrary + NotSet + + + + .pyd + + + + + + + + + + + _CONSOLE;%(PreprocessorDefinitions) + + + Console + + + + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + false + + + + + + \ No newline at end of file diff --git a/PCbuild/_testconsole.vcxproj.filters b/PCbuild/_testconsole.vcxproj.filters new file mode 100644 --- /dev/null +++ b/PCbuild/_testconsole.vcxproj.filters @@ -0,0 +1,22 @@ +? + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -61,7 +61,7 @@ - + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -92,6 +92,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyshellext", "pyshellext.vcxproj", "{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testconsole", "_testconsole.vcxproj", "{B244E787-C445-441C-BDF4-5A4F1A3A1E51}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -708,6 +710,22 @@ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.Build.0 = Release|Win32 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.ActiveCfg = Release|x64 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.Build.0 = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|Win32.ActiveCfg = Debug|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|Win32.Build.0 = Debug|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|x64.ActiveCfg = Debug|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|x64.Build.0 = Debug|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|Win32.ActiveCfg = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|Win32.Build.0 = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|x64.ActiveCfg = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|x64.Build.0 = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|Win32.ActiveCfg = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|Win32.Build.0 = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|x64.ActiveCfg = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|x64.Build.0 = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|Win32.ActiveCfg = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|Win32.Build.0 = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|x64.ActiveCfg = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs --- a/Tools/msi/test/test_files.wxs +++ b/Tools/msi/test/test_files.wxs @@ -17,6 +17,9 @@ + + + @@ -37,6 +40,9 @@ + + + @@ -57,6 +63,9 @@ + + + @@ -72,6 +81,9 @@ + + + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 12:12:56 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 03 Oct 2016 16:12:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjE3?= =?utf-8?q?=3A_Adds_=5Ftestconsole_module_to_test_console_input=2E_Fixes_s?= =?utf-8?q?ome_issues?= Message-ID: <20161003161251.17319.43484.F796067C@psf.io> https://hg.python.org/cpython/rev/363888141f41 changeset: 104263:363888141f41 branch: 3.6 parent: 104261:0e0189b47291 user: Steve Dower date: Mon Oct 03 09:04:58 2016 -0700 summary: Issue #28217: Adds _testconsole module to test console input. Fixes some issues found by the tests. files: Lib/test/test_winconsoleio.py | 70 +++++++- Misc/NEWS | 4 + Modules/_io/_iomodule.h | 3 +- Modules/_io/winconsoleio.c | 54 ++++- PC/_testconsole.c | 131 +++++++++++++++ PC/clinic/_testconsole.c.h | 82 +++++++++ PCbuild/_testconsole.vcxproj | 83 +++++++++ PCbuild/_testconsole.vcxproj.filters | 22 ++ PCbuild/pcbuild.proj | 2 +- PCbuild/pcbuild.sln | 18 ++ Tools/msi/test/test_files.wxs | 12 + 11 files changed, 460 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py --- a/Lib/test/test_winconsoleio.py +++ b/Lib/test/test_winconsoleio.py @@ -1,12 +1,4 @@ '''Tests for WindowsConsoleIO - -Unfortunately, most testing requires interactive use, since we have no -API to read back from a real console, and this class is only for use -with real consoles. - -Instead, we validate that basic functionality such as opening, closing -and in particular fileno() work, but are forced to leave real testing -to real people with real keyborads. ''' import io @@ -16,6 +8,8 @@ if sys.platform != 'win32': raise unittest.SkipTest("test only relevant on win32") +from _testconsole import write_input + ConIO = io._WindowsConsoleIO class WindowsConsoleIOTests(unittest.TestCase): @@ -83,5 +77,65 @@ f.close() f.close() + def assertStdinRoundTrip(self, text): + stdin = open('CONIN$', 'r') + old_stdin = sys.stdin + try: + sys.stdin = stdin + write_input( + stdin.buffer.raw, + (text + '\r\n').encode('utf-16-le', 'surrogatepass') + ) + actual = input() + finally: + sys.stdin = old_stdin + self.assertEqual(actual, text) + + def test_input(self): + # ASCII + self.assertStdinRoundTrip('abc123') + # Non-ASCII + self.assertStdinRoundTrip('??????') + # Combining characters + self.assertStdinRoundTrip('A?B ??AA?') + # Non-BMP + self.assertStdinRoundTrip('\U00100000\U0010ffff\U0010fffd') + + def test_partial_reads(self): + # Test that reading less than 1 full character works when stdin + # contains multibyte UTF-8 sequences + source = '??????\r\n'.encode('utf-16-le') + expected = '??????\r\n'.encode('utf-8') + for read_count in range(1, 16): + stdin = open('CONIN$', 'rb', buffering=0) + write_input(stdin, source) + + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b + + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) + stdin.close() + + def test_partial_surrogate_reads(self): + # Test that reading less than 1 full character works when stdin + # contains surrogate pairs that cannot be decoded to UTF-8 without + # reading an extra character. + source = '\U00101FFF\U00101001\r\n'.encode('utf-16-le') + expected = '\U00101FFF\U00101001\r\n'.encode('utf-8') + for read_count in range(1, 16): + stdin = open('CONIN$', 'rb', buffering=0) + write_input(stdin, source) + + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b + + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) + stdin.close() + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -186,6 +186,10 @@ - Issue #15819: Remove redundant include search directory option for building outside the source tree. +Tests +----- + +- Issue #28217: Adds _testconsole module to test console input. What's New in Python 3.6.0 beta 1 ================================= diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -22,7 +22,8 @@ #ifndef Py_LIMITED_API #ifdef MS_WINDOWS extern PyTypeObject PyWindowsConsoleIO_Type; -#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type)) +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type; +#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), (PyTypeObject*)_PyWindowsConsoleIO_Type)) #endif /* MS_WINDOWS */ #endif /* Py_LIMITED_API */ diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -39,6 +39,11 @@ /* BUFMAX determines how many bytes can be read in one go. */ #define BUFMAX (32*1024*1024) +/* SMALLBUF determines how many utf-8 characters will be + buffered within the stream, in order to support reads + of less than one character */ +#define SMALLBUF 4 + char _get_console_type(HANDLE handle) { DWORD mode, peek_count; @@ -125,7 +130,8 @@ unsigned int blksize; PyObject *weakreflist; PyObject *dict; - char buf[4]; + char buf[SMALLBUF]; + wchar_t wbuf; } winconsoleio; PyTypeObject PyWindowsConsoleIO_Type; @@ -500,11 +506,11 @@ static DWORD _buflen(winconsoleio *self) { - for (DWORD i = 0; i < 4; ++i) { + for (DWORD i = 0; i < SMALLBUF; ++i) { if (!self->buf[i]) return i; } - return 4; + return SMALLBUF; } static DWORD @@ -513,12 +519,10 @@ DWORD n = 0; while (self->buf[0] && len--) { - n += 1; - buf[0] = self->buf[0]; - self->buf[0] = self->buf[1]; - self->buf[1] = self->buf[2]; - self->buf[2] = self->buf[3]; - self->buf[3] = 0; + buf[n++] = self->buf[0]; + for (int i = 1; i < SMALLBUF; ++i) + self->buf[i - 1] = self->buf[i]; + self->buf[SMALLBUF - 1] = 0; } return n; @@ -531,10 +535,13 @@ wchar_t *buf = (wchar_t*)PyMem_Malloc(maxlen * sizeof(wchar_t)); if (!buf) goto error; + *readlen = 0; + //DebugBreak(); Py_BEGIN_ALLOW_THREADS - for (DWORD off = 0; off < maxlen; off += BUFSIZ) { + DWORD off = 0; + while (off < maxlen) { DWORD n, len = min(maxlen - off, BUFSIZ); SetLastError(0); BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); @@ -550,7 +557,7 @@ err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) - == WAIT_OBJECT_0) { + == WAIT_OBJECT_0) { ResetEvent(hInterruptEvent); Py_BLOCK_THREADS sig = PyErr_CheckSignals(); @@ -568,7 +575,30 @@ /* If the buffer ended with a newline, break out */ if (buf[*readlen - 1] == '\n') break; + /* If the buffer ends with a high surrogate, expand the + buffer and read an extra character. */ + WORD char_type; + if (off + BUFSIZ >= maxlen && + GetStringTypeW(CT_CTYPE3, &buf[*readlen - 1], 1, &char_type) && + char_type == C3_HIGHSURROGATE) { + wchar_t *newbuf; + maxlen += 1; + Py_BLOCK_THREADS + newbuf = (wchar_t*)PyMem_Realloc(buf, maxlen * sizeof(wchar_t)); + Py_UNBLOCK_THREADS + if (!newbuf) { + sig = -1; + break; + } + buf = newbuf; + /* Only advance by n and not BUFSIZ in this case */ + off += n; + continue; + } + + off += BUFSIZ; } + Py_END_ALLOW_THREADS if (sig) @@ -1110,4 +1140,6 @@ 0, /* tp_finalize */ }; +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type = (PyObject*)&PyWindowsConsoleIO_Type; + #endif /* MS_WINDOWS */ diff --git a/PC/_testconsole.c b/PC/_testconsole.c new file mode 100644 --- /dev/null +++ b/PC/_testconsole.c @@ -0,0 +1,131 @@ + +/* Testing module for multi-phase initialization of extension modules (PEP 489) + */ + +#include "Python.h" + +#ifdef MS_WINDOWS + +#include "..\modules\_io\_iomodule.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + + /* The full definition is in iomodule. We reproduce + enough here to get the handle, which is all we want. */ +typedef struct { + PyObject_HEAD + HANDLE handle; +} winconsoleio; + + +static int execfunc(PyObject *m) +{ + return 0; +} + +PyModuleDef_Slot testconsole_slots[] = { + {Py_mod_exec, execfunc}, + {0, NULL}, +}; + +/*[clinic input] +module _testconsole + +_testconsole.write_input + file: object + s: PyBytesObject + +Writes UTF-16-LE encoded bytes to the console as if typed by a user. +[clinic start generated code]*/ + +static PyObject * +_testconsole_write_input_impl(PyObject *module, PyObject *file, + PyBytesObject *s) +/*[clinic end generated code: output=48f9563db34aedb3 input=4c774f2d05770bc6]*/ +{ + INPUT_RECORD *rec = NULL; + + if (!PyWindowsConsoleIO_Check(file)) { + PyErr_SetString(PyExc_TypeError, "expected raw console object"); + return NULL; + } + + const wchar_t *p = (const wchar_t *)PyBytes_AS_STRING(s); + DWORD size = (DWORD)PyBytes_GET_SIZE(s) / sizeof(wchar_t); + + rec = (INPUT_RECORD*)PyMem_Malloc(sizeof(INPUT_RECORD) * size); + if (!rec) + goto error; + memset(rec, 0, sizeof(INPUT_RECORD) * size); + + INPUT_RECORD *prec = rec; + for (DWORD i = 0; i < size; ++i, ++p, ++prec) { + prec->EventType = KEY_EVENT; + prec->Event.KeyEvent.bKeyDown = TRUE; + prec->Event.KeyEvent.wRepeatCount = 10; + prec->Event.KeyEvent.uChar.UnicodeChar = *p; + } + + HANDLE hInput = ((winconsoleio*)file)->handle; + DWORD total = 0; + while (total < size) { + DWORD wrote; + if (!WriteConsoleInputW(hInput, &rec[total], (size - total), &wrote)) { + PyErr_SetFromWindowsErr(0); + goto error; + } + total += wrote; + } + + PyMem_Free((void*)rec); + + Py_RETURN_NONE; +error: + if (rec) + PyMem_Free((void*)rec); + return NULL; +} + +/*[clinic input] +_testconsole.read_output + file: object + +Reads a str from the console as written to stdout. +[clinic start generated code]*/ + +static PyObject * +_testconsole_read_output_impl(PyObject *module, PyObject *file) +/*[clinic end generated code: output=876310d81a73e6d2 input=b3521f64b1b558e3]*/ +{ + Py_RETURN_NONE; +} + +#include "clinic\_testconsole.c.h" + +PyMethodDef testconsole_methods[] = { + _TESTCONSOLE_WRITE_INPUT_METHODDEF + _TESTCONSOLE_READ_OUTPUT_METHODDEF + {NULL, NULL} +}; + +static PyModuleDef testconsole_def = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_testconsole", /* m_name */ + PyDoc_STR("Test module for the Windows console"), /* m_doc */ + 0, /* m_size */ + testconsole_methods, /* m_methods */ + testconsole_slots, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyMODINIT_FUNC +PyInit__testconsole(PyObject *spec) +{ + return PyModuleDef_Init(&testconsole_def); +} + +#endif /* MS_WINDOWS */ diff --git a/PC/clinic/_testconsole.c.h b/PC/clinic/_testconsole.c.h new file mode 100644 --- /dev/null +++ b/PC/clinic/_testconsole.c.h @@ -0,0 +1,82 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_testconsole_write_input__doc__, +"write_input($module, /, file, s)\n" +"--\n" +"\n" +"Writes UTF-16-LE encoded bytes to the console as if typed by a user."); + +#define _TESTCONSOLE_WRITE_INPUT_METHODDEF \ + {"write_input", (PyCFunction)_testconsole_write_input, METH_FASTCALL, _testconsole_write_input__doc__}, + +static PyObject * +_testconsole_write_input_impl(PyObject *module, PyObject *file, + PyBytesObject *s); + +static PyObject * +_testconsole_write_input(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"file", "s", NULL}; + static _PyArg_Parser _parser = {"OS:write_input", _keywords, 0}; + PyObject *file; + PyBytesObject *s; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &file, &s)) { + goto exit; + } + return_value = _testconsole_write_input_impl(module, file, s); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_testconsole_read_output__doc__, +"read_output($module, /, file)\n" +"--\n" +"\n" +"Reads a str from the console as written to stdout."); + +#define _TESTCONSOLE_READ_OUTPUT_METHODDEF \ + {"read_output", (PyCFunction)_testconsole_read_output, METH_FASTCALL, _testconsole_read_output__doc__}, + +static PyObject * +_testconsole_read_output_impl(PyObject *module, PyObject *file); + +static PyObject * +_testconsole_read_output(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"file", NULL}; + static _PyArg_Parser _parser = {"O:read_output", _keywords, 0}; + PyObject *file; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &file)) { + goto exit; + } + return_value = _testconsole_read_output_impl(module, file); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#ifndef _TESTCONSOLE_WRITE_INPUT_METHODDEF + #define _TESTCONSOLE_WRITE_INPUT_METHODDEF +#endif /* !defined(_TESTCONSOLE_WRITE_INPUT_METHODDEF) */ + +#ifndef _TESTCONSOLE_READ_OUTPUT_METHODDEF + #define _TESTCONSOLE_READ_OUTPUT_METHODDEF +#endif /* !defined(_TESTCONSOLE_READ_OUTPUT_METHODDEF) */ +/*[clinic end generated code: output=3a8dc0c421807c41 input=a9049054013a1b77]*/ diff --git a/PCbuild/_testconsole.vcxproj b/PCbuild/_testconsole.vcxproj new file mode 100644 --- /dev/null +++ b/PCbuild/_testconsole.vcxproj @@ -0,0 +1,83 @@ +? + + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + Win32 + + + Release + x64 + + + + {B244E787-C445-441C-BDF4-5A4F1A3A1E51} + Win32Proj + _testconsole + false + + + + + DynamicLibrary + NotSet + + + + .pyd + + + + + + + + + + + _CONSOLE;%(PreprocessorDefinitions) + + + Console + + + + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + false + + + + + + \ No newline at end of file diff --git a/PCbuild/_testconsole.vcxproj.filters b/PCbuild/_testconsole.vcxproj.filters new file mode 100644 --- /dev/null +++ b/PCbuild/_testconsole.vcxproj.filters @@ -0,0 +1,22 @@ +? + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -61,7 +61,7 @@ - + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -92,6 +92,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyshellext", "pyshellext.vcxproj", "{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testconsole", "_testconsole.vcxproj", "{B244E787-C445-441C-BDF4-5A4F1A3A1E51}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -708,6 +710,22 @@ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.Build.0 = Release|Win32 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.ActiveCfg = Release|x64 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.Build.0 = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|Win32.ActiveCfg = Debug|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|Win32.Build.0 = Debug|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|x64.ActiveCfg = Debug|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|x64.Build.0 = Debug|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|Win32.ActiveCfg = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|Win32.Build.0 = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|x64.ActiveCfg = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|x64.Build.0 = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|Win32.ActiveCfg = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|Win32.Build.0 = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|x64.ActiveCfg = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|x64.Build.0 = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|Win32.ActiveCfg = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|Win32.Build.0 = Release|Win32 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|x64.ActiveCfg = Release|x64 + {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs --- a/Tools/msi/test/test_files.wxs +++ b/Tools/msi/test/test_files.wxs @@ -17,6 +17,9 @@ + + + @@ -37,6 +40,9 @@ + + + @@ -57,6 +63,9 @@ + + + @@ -72,6 +81,9 @@ + + + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 12:15:52 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 03 Oct 2016 16:15:52 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjE4?= =?utf-8?q?=3A_Fixes_versionadded_description_in_using/windows=2Erst?= Message-ID: <20161003161550.82076.43904.99D0A2C5@psf.io> https://hg.python.org/cpython/rev/de79cc895203 changeset: 104265:de79cc895203 branch: 3.6 parent: 104263:363888141f41 user: Steve Dower date: Mon Oct 03 09:15:27 2016 -0700 summary: Issue #28218: Fixes versionadded description in using/windows.rst files: Doc/using/windows.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -818,7 +818,7 @@ .. versionchanged:: 3.6 - * Adds ``sys.path`` file support and removes ``applocal`` option from + * Adds ``._pth`` file support and removes ``applocal`` option from ``pyvenv.cfg``. * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent to the executable. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 12:16:00 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 03 Oct 2016 16:16:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_from_3=2E6?= Message-ID: <20161003161550.5092.27522.D8B50906@psf.io> https://hg.python.org/cpython/rev/14c52bb996be changeset: 104266:14c52bb996be parent: 104264:3ec6a610e93e parent: 104265:de79cc895203 user: Steve Dower date: Mon Oct 03 09:15:39 2016 -0700 summary: Merge from 3.6 files: Doc/using/windows.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -818,7 +818,7 @@ .. versionchanged:: 3.6 - * Adds ``sys.path`` file support and removes ``applocal`` option from + * Adds ``._pth`` file support and removes ``applocal`` option from ``pyvenv.cfg``. * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent to the executable. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 14:16:42 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 03 Oct 2016 18:16:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_myself_to_the_ACKS_fil?= =?utf-8?q?e=2E?= Message-ID: <20161003181641.95323.51932.1F9D50AA@psf.io> https://hg.python.org/cpython/rev/3d440ae207d9 changeset: 104267:3d440ae207d9 user: Steve Dower date: Mon Oct 03 11:16:17 2016 -0700 summary: Add myself to the ACKS file. 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 @@ -371,6 +371,7 @@ Dima Dorfman Yves Dorfsman Michael Dorman +Steve Dower Cesar Douady Dean Draayer Fred L. Drake, Jr. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 14:46:14 2016 From: python-checkins at python.org (vinay.sajip) Date: Mon, 03 Oct 2016 18:46:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2328335=3A_used_?= =?utf-8?q?=27raise_from=27_in_logging_configuration_code=2E?= Message-ID: <20161003184613.79323.36326.8C3B9504@psf.io> https://hg.python.org/cpython/rev/69bf09bf4952 changeset: 104268:69bf09bf4952 user: Vinay Sajip date: Mon Oct 03 19:45:50 2016 +0100 summary: Closes #28335: used 'raise from' in logging configuration code. files: Lib/logging/config.py | 32 +++++++++++++++--------------- 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -1,4 +1,4 @@ -# Copyright 2001-2014 by Vinay Sajip. All Rights Reserved. +# Copyright 2001-2016 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, @@ -19,7 +19,7 @@ is based on PEP 282 and comments thereto in comp.lang.python, and influenced by Apache's log4j system. -Copyright (C) 2001-2014 Vinay Sajip. All Rights Reserved. +Copyright (C) 2001-2016 Vinay Sajip. All Rights Reserved. To use, simply 'import logging' and log away! """ @@ -509,21 +509,21 @@ handler.setLevel(logging._checkLevel(level)) except Exception as e: raise ValueError('Unable to configure handler ' - '%r: %s' % (name, e)) + '%r' % name) from e loggers = config.get('loggers', EMPTY_DICT) for name in loggers: try: self.configure_logger(name, loggers[name], True) except Exception as e: raise ValueError('Unable to configure logger ' - '%r: %s' % (name, e)) + '%r' % name) from e root = config.get('root', None) if root: try: self.configure_root(root, True) except Exception as e: raise ValueError('Unable to configure root ' - 'logger: %s' % e) + 'logger') from e else: disable_existing = config.pop('disable_existing_loggers', True) @@ -538,7 +538,7 @@ formatters[name]) except Exception as e: raise ValueError('Unable to configure ' - 'formatter %r: %s' % (name, e)) + 'formatter %r' % name) from e # Next, do filters - they don't refer to anything else, either filters = config.get('filters', EMPTY_DICT) for name in filters: @@ -546,7 +546,7 @@ filters[name] = self.configure_filter(filters[name]) except Exception as e: raise ValueError('Unable to configure ' - 'filter %r: %s' % (name, e)) + 'filter %r' % name) from e # Next, do handlers - they refer to formatters and filters # As handlers can refer to other handlers, sort the keys @@ -559,11 +559,11 @@ handler.name = name handlers[name] = handler except Exception as e: - if 'target not configured yet' in str(e): + if 'Unable to set target handler' in str(e): deferred.append(name) else: raise ValueError('Unable to configure handler ' - '%r: %s' % (name, e)) + '%r' % name) from e # Now do any that were deferred for name in deferred: @@ -573,7 +573,7 @@ handlers[name] = handler except Exception as e: raise ValueError('Unable to configure handler ' - '%r: %s' % (name, e)) + '%r' % name) from e # Next, do loggers - they refer to handlers and filters @@ -612,7 +612,7 @@ self.configure_logger(name, loggers[name]) except Exception as e: raise ValueError('Unable to configure logger ' - '%r: %s' % (name, e)) + '%r' % name) from e #Disable any old loggers. There's no point deleting #them as other threads may continue to hold references @@ -637,7 +637,7 @@ self.configure_root(root) except Exception as e: raise ValueError('Unable to configure root ' - 'logger: %s' % e) + 'logger') from e finally: logging._releaseLock() @@ -684,7 +684,7 @@ try: filterer.addFilter(self.config['filters'][f]) except Exception as e: - raise ValueError('Unable to add filter %r: %s' % (f, e)) + raise ValueError('Unable to add filter %r' % f) from e def configure_handler(self, config): """Configure a handler from a dictionary.""" @@ -695,7 +695,7 @@ formatter = self.config['formatters'][formatter] except Exception as e: raise ValueError('Unable to set formatter ' - '%r: %s' % (formatter, e)) + '%r' % formatter) from e level = config.pop('level', None) filters = config.pop('filters', None) if '()' in config: @@ -717,7 +717,7 @@ config['target'] = th except Exception as e: raise ValueError('Unable to set target handler ' - '%r: %s' % (config['target'], e)) + '%r' % config['target']) from e elif issubclass(klass, logging.handlers.SMTPHandler) and\ 'mailhost' in config: config['mailhost'] = self.as_tuple(config['mailhost']) @@ -755,7 +755,7 @@ try: logger.addHandler(self.config['handlers'][h]) except Exception as e: - raise ValueError('Unable to add handler %r: %s' % (h, e)) + raise ValueError('Unable to add handler %r' % h) from e def common_logger_config(self, logger, config, incremental=False): """ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 3 14:51:02 2016 From: python-checkins at python.org (vinay.sajip) Date: Mon, 03 Oct 2016 18:51:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328335=3A_made_min?= =?utf-8?q?or_improvement_to_implementation=2E?= Message-ID: <20161003185101.85654.79340.3F7DFBB6@psf.io> https://hg.python.org/cpython/rev/8c005be54305 changeset: 104269:8c005be54305 user: Vinay Sajip date: Mon Oct 03 19:50:56 2016 +0100 summary: Issue #28335: made minor improvement to implementation. files: Lib/logging/config.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -559,7 +559,7 @@ handler.name = name handlers[name] = handler except Exception as e: - if 'Unable to set target handler' in str(e): + if 'target not configured yet' in str(e.__cause__): deferred.append(name) else: raise ValueError('Unable to configure handler ' -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Mon Oct 3 14:56:38 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 3 Oct 2016 19:56:38 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-03 Message-ID: <7f95a77c-b236-4a5c-877b-0cbe6bfe2668@irsmsx106.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-03 15:23:57 +0000 commit: a0b9c4f98573 previous commit: f256bd5b8418 revision date: 2016-10-02 18:16:28 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% 0.06% 3.76% 7.66% :-) pybench 0.19% -0.16% 6.05% 3.65% :-( regex_v8 0.65% -0.01% -2.22% 10.55% :-) nbody 0.19% -0.16% 7.28% 4.83% :-| json_dump_v2 0.33% 0.27% 1.88% 10.49% :-| normal_startup 0.59% 0.32% -0.53% 2.75% :-) ssbench 0.17% 0.06% 2.14% 1.74% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-03/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Mon Oct 3 14:58:31 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 3 Oct 2016 19:58:31 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-03 Message-ID: Results for project Python default, build date 2016-10-03 14:39:26 +0000 commit: 36b052adf5a7 previous commit: 6619b76053a5 revision date: 2016-10-02 19:00:05 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.14% -0.03% 5.00% 13.11% :-) pybench 0.13% 1.33% 5.38% 4.87% :-( regex_v8 3.72% -2.73% -4.69% 1.91% :-) nbody 0.11% 0.66% 2.70% 2.18% :-( json_dump_v2 0.30% -4.72% -13.36% 18.17% :-) normal_startup 0.88% 0.03% 3.74% 6.12% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-03/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Tue Oct 4 02:25:02 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 04 Oct 2016 06:25:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2321124=2C_=232833?= =?utf-8?q?7=3A_Call_PyType=5FReady_on_unpackiter=5Ftype=2E?= Message-ID: <20161004062502.76027.58147.DC2D1C7F@psf.io> https://hg.python.org/cpython/rev/c4eb211fb38b changeset: 104270:c4eb211fb38b user: Zachary Ware date: Tue Oct 04 01:20:21 2016 -0500 summary: Closes #21124, #28337: Call PyType_Ready on unpackiter_type. Patch by Masayuki Yamamoto. files: Modules/_struct.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2301,6 +2301,9 @@ if (PyType_Ready(&PyStructType) < 0) return NULL; + if (PyType_Ready(&unpackiter_type) < 0) + return NULL; + /* Check endian and swap in faster functions */ { const formatdef *native = native_table; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 03:01:19 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Oct 2016 07:01:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_merge_3=2E5_=28=2326617=29?= Message-ID: <20161004070111.75748.37125.2FBF94B6@psf.io> https://hg.python.org/cpython/rev/520cb70ecb90 changeset: 104272:520cb70ecb90 branch: 3.6 parent: 104265:de79cc895203 parent: 104271:c9b7272e2553 user: Benjamin Peterson date: Tue Oct 04 00:00:23 2016 -0700 summary: merge 3.5 (#26617) files: Lib/test/test_weakref.py | 8 ++++++++ Misc/NEWS | 2 ++ Objects/typeobject.c | 27 ++++++++++++++------------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -845,6 +845,14 @@ with self.assertRaises(AttributeError): ref1.__callback__ = lambda ref: None + def test_callback_gcs(self): + class ObjectWithDel(Object): + def __del__(self): pass + x = ObjectWithDel(1) + ref1 = weakref.ref(x, lambda ref: support.gc_collect()) + del x + support.gc_collect() + class SubclassableWeakrefTestCase(TestBase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #26617: Fix crash when GC runs during weakref callbacks. + - Issue #27942: String constants now interned recursively in tuples and frozensets. - Issue #21578: Fixed misleading error message when ImportError called with diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1136,11 +1136,6 @@ Py_TRASHCAN_SAFE_BEGIN(self); --_PyTrash_delete_nesting; -- tstate->trash_delete_nesting; - /* DO NOT restore GC tracking at this point. weakref callbacks - * (if any, and whether directly here or indirectly in something we - * call) may trigger GC, and if self is tracked at that point, it - * will look like trash to GC and GC will try to delete self again. - */ /* Find the nearest base with a different tp_dealloc */ base = type; @@ -1151,30 +1146,36 @@ has_finalizer = type->tp_finalize || type->tp_del; - /* Maybe call finalizer; exit early if resurrected */ - if (has_finalizer) + if (type->tp_finalize) { _PyObject_GC_TRACK(self); - - if (type->tp_finalize) { if (PyObject_CallFinalizerFromDealloc(self) < 0) { /* Resurrected */ goto endlabel; } - } - /* If we added a weaklist, we clear it. Do this *before* calling - tp_del, clearing slots, or clearing the instance dict. */ + _PyObject_GC_UNTRACK(self); + } + /* + If we added a weaklist, we clear it. Do this *before* calling tp_del, + clearing slots, or clearing the instance dict. + + GC tracking must be off at this point. weakref callbacks (if any, and + whether directly here or indirectly in something we call) may trigger GC, + and if self is tracked at that point, it will look like trash to GC and GC + will try to delete self again. + */ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) PyObject_ClearWeakRefs(self); if (type->tp_del) { + _PyObject_GC_TRACK(self); type->tp_del(self); if (self->ob_refcnt > 0) { /* Resurrected */ goto endlabel; } + _PyObject_GC_UNTRACK(self); } if (has_finalizer) { - _PyObject_GC_UNTRACK(self); /* New weakrefs could be created during the finalizer call. If this occurs, clear them out without calling their finalizers since they might rely on part of the object -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 03:01:19 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Oct 2016 07:01:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_ensure_gc_trac?= =?utf-8?q?king_is_off_when_invoking_weakref_callbacks_=28closes_=2326617?= =?utf-8?q?=29?= Message-ID: <20161004070110.82463.14352.A9C7BF9E@psf.io> https://hg.python.org/cpython/rev/c9b7272e2553 changeset: 104271:c9b7272e2553 branch: 3.5 parent: 104260:b24d0f274623 user: Benjamin Peterson date: Tue Oct 04 00:00:02 2016 -0700 summary: ensure gc tracking is off when invoking weakref callbacks (closes #26617) files: Lib/test/test_weakref.py | 8 ++++++++ Misc/NEWS | 2 ++ Objects/typeobject.c | 27 ++++++++++++++------------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -845,6 +845,14 @@ with self.assertRaises(AttributeError): ref1.__callback__ = lambda ref: None + def test_callback_gcs(self): + class ObjectWithDel(Object): + def __del__(self): pass + x = ObjectWithDel(1) + ref1 = weakref.ref(x, lambda ref: support.gc_collect()) + del x + support.gc_collect() + class SubclassableWeakrefTestCase(TestBase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #26617: Fix crash when GC runs during weakref callbacks. + - Issue #27942: String constants now interned recursively in tuples and frozensets. - Issue #21578: Fixed misleading error message when ImportError called with diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1123,11 +1123,6 @@ Py_TRASHCAN_SAFE_BEGIN(self); --_PyTrash_delete_nesting; -- tstate->trash_delete_nesting; - /* DO NOT restore GC tracking at this point. weakref callbacks - * (if any, and whether directly here or indirectly in something we - * call) may trigger GC, and if self is tracked at that point, it - * will look like trash to GC and GC will try to delete self again. - */ /* Find the nearest base with a different tp_dealloc */ base = type; @@ -1138,30 +1133,36 @@ has_finalizer = type->tp_finalize || type->tp_del; - /* Maybe call finalizer; exit early if resurrected */ - if (has_finalizer) + if (type->tp_finalize) { _PyObject_GC_TRACK(self); - - if (type->tp_finalize) { if (PyObject_CallFinalizerFromDealloc(self) < 0) { /* Resurrected */ goto endlabel; } - } - /* If we added a weaklist, we clear it. Do this *before* calling - tp_del, clearing slots, or clearing the instance dict. */ + _PyObject_GC_UNTRACK(self); + } + /* + If we added a weaklist, we clear it. Do this *before* calling tp_del, + clearing slots, or clearing the instance dict. + + GC tracking must be off at this point. weakref callbacks (if any, and + whether directly here or indirectly in something we call) may trigger GC, + and if self is tracked at that point, it will look like trash to GC and GC + will try to delete self again. + */ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) PyObject_ClearWeakRefs(self); if (type->tp_del) { + _PyObject_GC_TRACK(self); type->tp_del(self); if (self->ob_refcnt > 0) { /* Resurrected */ goto endlabel; } + _PyObject_GC_UNTRACK(self); } if (has_finalizer) { - _PyObject_GC_UNTRACK(self); /* New weakrefs could be created during the finalizer call. If this occurs, clear them out without calling their finalizers since they might rely on part of the object -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 03:01:19 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Oct 2016 07:01:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42ICgjMjY2MTcp?= Message-ID: <20161004070111.82118.83041.B577ECC1@psf.io> https://hg.python.org/cpython/rev/c1d0df056c19 changeset: 104273:c1d0df056c19 parent: 104269:8c005be54305 parent: 104272:520cb70ecb90 user: Benjamin Peterson date: Tue Oct 04 00:00:35 2016 -0700 summary: merge 3.6 (#26617) files: Lib/test/test_weakref.py | 8 ++++++++ Misc/NEWS | 2 ++ Objects/typeobject.c | 27 ++++++++++++++------------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -845,6 +845,14 @@ with self.assertRaises(AttributeError): ref1.__callback__ = lambda ref: None + def test_callback_gcs(self): + class ObjectWithDel(Object): + def __del__(self): pass + x = ObjectWithDel(1) + ref1 = weakref.ref(x, lambda ref: support.gc_collect()) + del x + support.gc_collect() + class SubclassableWeakrefTestCase(TestBase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #26617: Fix crash when GC runs during weakref callbacks. + - Issue #27942: String constants now interned recursively in tuples and frozensets. - Issue #28289: ImportError.__init__ now resets not specified attributes. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1136,11 +1136,6 @@ Py_TRASHCAN_SAFE_BEGIN(self); --_PyTrash_delete_nesting; -- tstate->trash_delete_nesting; - /* DO NOT restore GC tracking at this point. weakref callbacks - * (if any, and whether directly here or indirectly in something we - * call) may trigger GC, and if self is tracked at that point, it - * will look like trash to GC and GC will try to delete self again. - */ /* Find the nearest base with a different tp_dealloc */ base = type; @@ -1151,30 +1146,36 @@ has_finalizer = type->tp_finalize || type->tp_del; - /* Maybe call finalizer; exit early if resurrected */ - if (has_finalizer) + if (type->tp_finalize) { _PyObject_GC_TRACK(self); - - if (type->tp_finalize) { if (PyObject_CallFinalizerFromDealloc(self) < 0) { /* Resurrected */ goto endlabel; } - } - /* If we added a weaklist, we clear it. Do this *before* calling - tp_del, clearing slots, or clearing the instance dict. */ + _PyObject_GC_UNTRACK(self); + } + /* + If we added a weaklist, we clear it. Do this *before* calling tp_del, + clearing slots, or clearing the instance dict. + + GC tracking must be off at this point. weakref callbacks (if any, and + whether directly here or indirectly in something we call) may trigger GC, + and if self is tracked at that point, it will look like trash to GC and GC + will try to delete self again. + */ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) PyObject_ClearWeakRefs(self); if (type->tp_del) { + _PyObject_GC_TRACK(self); type->tp_del(self); if (self->ob_refcnt > 0) { /* Resurrected */ goto endlabel; } + _PyObject_GC_UNTRACK(self); } if (has_finalizer) { - _PyObject_GC_UNTRACK(self); /* New weakrefs could be created during the finalizer call. If this occurs, clear them out without calling their finalizers since they might rely on part of the object -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 03:01:19 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Oct 2016 07:01:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge_heads?= Message-ID: <20161004070111.85846.45791.AFF4AD58@psf.io> https://hg.python.org/cpython/rev/3fed30fa37f4 changeset: 104274:3fed30fa37f4 parent: 104273:c1d0df056c19 parent: 104270:c4eb211fb38b user: Benjamin Peterson date: Tue Oct 04 00:01:03 2016 -0700 summary: merge heads files: Modules/_struct.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2301,6 +2301,9 @@ if (PyType_Ready(&PyStructType) < 0) return NULL; + if (PyType_Ready(&unpackiter_type) < 0) + return NULL; + /* Check endian and swap in faster functions */ { const formatdef *native = native_table; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:16 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4MzUw?= =?utf-8?q?=3A_String_constants_with_null_character_no_longer_interned=2E?= Message-ID: <20161004152515.20229.53267.FAA4FC29@psf.io> https://hg.python.org/cpython/rev/522adc2e082a changeset: 104275:522adc2e082a branch: 2.7 parent: 104251:a0b9c4f98573 user: Serhiy Storchaka date: Tue Oct 04 18:17:08 2016 +0300 summary: Issue #28350: String constants with null character no longer interned. files: Lib/test/test_code.py | 20 +++++++++++++++++--- Misc/NEWS | 2 ++ Objects/codeobject.c | 13 ++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -112,19 +112,27 @@ self.assertEqual(co.co_name, "funcname") self.assertEqual(co.co_firstlineno, 15) + +def isinterned(s): + return s is intern(('_' + s + '_')[1:-1]) + class CodeConstsTest(unittest.TestCase): def find_const(self, consts, value): for v in consts: if v == value: return v - self.assertIn(value, consts) # rises an exception - self.fail('Should be never reached') + self.assertIn(value, consts) # raises an exception + self.fail('Should never be reached') def assertIsInterned(self, s): - if s is not intern(s): + if not isinterned(s): self.fail('String %r is not interned' % (s,)) + def assertIsNotInterned(self, s): + if isinterned(s): + self.fail('String %r is interned' % (s,)) + @cpython_only def test_interned_string(self): co = compile('res = "str_value"', '?', 'exec') @@ -143,6 +151,12 @@ return a self.assertIsInterned(f()) + @cpython_only + def test_interned_string_with_null(self): + co = compile(r'res = "str\0value!"', '?', 'exec') + v = self.find_const(co.co_consts, 'str\0value!') + self.assertIsNotInterned(v) + class CodeWeakRefTest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28350: String constants with null character no longer interned. + - Issue #27942: String constants now interned recursively in tuples and frozensets. - Issue #15578: Correctly incref the parent module while importing. diff --git a/Objects/codeobject.c b/Objects/codeobject.c --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -8,17 +8,20 @@ /* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */ static int -all_name_chars(unsigned char *s) +all_name_chars(PyObject *o) { static char ok_name_char[256]; - static unsigned char *name_chars = (unsigned char *)NAME_CHARS; + static const unsigned char *name_chars = (unsigned char *)NAME_CHARS; + const unsigned char *s, *e; if (ok_name_char[*name_chars] == 0) { - unsigned char *p; + const unsigned char *p; for (p = name_chars; *p; p++) ok_name_char[*p] = 1; } - while (*s) { + s = (unsigned char *)PyString_AS_STRING(o); + e = s + PyString_GET_SIZE(o); + while (s != e) { if (ok_name_char[*s++] == 0) return 0; } @@ -49,7 +52,7 @@ for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { PyObject *v = PyTuple_GET_ITEM(tuple, i); if (PyString_CheckExact(v)) { - if (all_name_chars((unsigned char *)PyString_AS_STRING(v))) { + if (all_name_chars(v)) { PyObject *w = v; PyString_InternInPlace(&v); if (w != v) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:16 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:16 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328350=3A_String_constants_with_null_character_n?= =?utf-8?q?o_longer_interned=2E?= Message-ID: <20161004152516.20168.65682.B34F2EBB@psf.io> https://hg.python.org/cpython/rev/563d523036c6 changeset: 104278:563d523036c6 parent: 104274:3fed30fa37f4 parent: 104277:8585b4de4fc0 user: Serhiy Storchaka date: Tue Oct 04 18:21:53 2016 +0300 summary: Issue #28350: String constants with null character no longer interned. files: Lib/test/test_code.py | 20 +++++++++++++++++--- Misc/NEWS | 2 ++ Objects/codeobject.c | 16 ++++++++-------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -135,19 +135,27 @@ self.assertEqual(co.co_name, "funcname") self.assertEqual(co.co_firstlineno, 15) + +def isinterned(s): + return s is sys.intern(('_' + s + '_')[1:-1]) + class CodeConstsTest(unittest.TestCase): def find_const(self, consts, value): for v in consts: if v == value: return v - self.assertIn(value, consts) # rises an exception - self.fail('Should be never reached') + self.assertIn(value, consts) # raises an exception + self.fail('Should never be reached') def assertIsInterned(self, s): - if s is not sys.intern(s): + if not isinterned(s): self.fail('String %r is not interned' % (s,)) + def assertIsNotInterned(self, s): + if isinterned(s): + self.fail('String %r is interned' % (s,)) + @cpython_only def test_interned_string(self): co = compile('res = "str_value"', '?', 'exec') @@ -172,6 +180,12 @@ return a self.assertIsInterned(f()) + @cpython_only + def test_interned_string_with_null(self): + co = compile(r'res = "str\0value!"', '?', 'exec') + v = self.find_const(co.co_consts, 'str\0value!') + self.assertIsNotInterned(v) + class CodeWeakRefTest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28350: String constants with null character no longer interned. + - Issue #26617: Fix crash when GC runs during weakref callbacks. - Issue #27942: String constants now interned recursively in tuples and frozensets. diff --git a/Objects/codeobject.c b/Objects/codeobject.c --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -19,21 +19,21 @@ all_name_chars(PyObject *o) { static char ok_name_char[256]; - static unsigned char *name_chars = (unsigned char *)NAME_CHARS; - PyUnicodeObject *u = (PyUnicodeObject *)o; - const unsigned char *s; + static const unsigned char *name_chars = (unsigned char *)NAME_CHARS; + const unsigned char *s, *e; - if (!PyUnicode_Check(o) || PyUnicode_READY(u) == -1 || - PyUnicode_MAX_CHAR_VALUE(u) >= 128) + if (!PyUnicode_Check(o) || PyUnicode_READY(o) == -1 || + !PyUnicode_IS_ASCII(o)) return 0; if (ok_name_char[*name_chars] == 0) { - unsigned char *p; + const unsigned char *p; for (p = name_chars; *p; p++) ok_name_char[*p] = 1; } - s = PyUnicode_1BYTE_DATA(u); - while (*s) { + s = PyUnicode_1BYTE_DATA(o); + e = s + PyUnicode_GET_LENGTH(o); + while (s != e) { if (ok_name_char[*s++] == 0) return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Null_merge?= Message-ID: <20161004152516.20094.10855.53508A4C@psf.io> https://hg.python.org/cpython/rev/4368f897b33e changeset: 104280:4368f897b33e branch: 3.6 parent: 104277:8585b4de4fc0 parent: 104279:b674fd340a23 user: Serhiy Storchaka date: Tue Oct 04 18:24:21 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNSk6?= =?utf-8?q?_Merge_heads?= Message-ID: <20161004152516.20251.43396.F0546F11@psf.io> https://hg.python.org/cpython/rev/b674fd340a23 changeset: 104279:b674fd340a23 branch: 3.5 parent: 104276:d7ab3241aef2 parent: 104271:c9b7272e2553 user: Serhiy Storchaka date: Tue Oct 04 18:23:55 2016 +0300 summary: Merge heads files: Lib/test/test_weakref.py | 8 ++++++++ Misc/NEWS | 2 ++ Objects/typeobject.c | 27 ++++++++++++++------------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -845,6 +845,14 @@ with self.assertRaises(AttributeError): ref1.__callback__ = lambda ref: None + def test_callback_gcs(self): + class ObjectWithDel(Object): + def __del__(self): pass + x = ObjectWithDel(1) + ref1 = weakref.ref(x, lambda ref: support.gc_collect()) + del x + support.gc_collect() + class SubclassableWeakrefTestCase(TestBase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,8 @@ - Issue #28350: String constants with null character no longer interned. +- Issue #26617: Fix crash when GC runs during weakref callbacks. + - Issue #27942: String constants now interned recursively in tuples and frozensets. - Issue #21578: Fixed misleading error message when ImportError called with diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1123,11 +1123,6 @@ Py_TRASHCAN_SAFE_BEGIN(self); --_PyTrash_delete_nesting; -- tstate->trash_delete_nesting; - /* DO NOT restore GC tracking at this point. weakref callbacks - * (if any, and whether directly here or indirectly in something we - * call) may trigger GC, and if self is tracked at that point, it - * will look like trash to GC and GC will try to delete self again. - */ /* Find the nearest base with a different tp_dealloc */ base = type; @@ -1138,30 +1133,36 @@ has_finalizer = type->tp_finalize || type->tp_del; - /* Maybe call finalizer; exit early if resurrected */ - if (has_finalizer) + if (type->tp_finalize) { _PyObject_GC_TRACK(self); - - if (type->tp_finalize) { if (PyObject_CallFinalizerFromDealloc(self) < 0) { /* Resurrected */ goto endlabel; } - } - /* If we added a weaklist, we clear it. Do this *before* calling - tp_del, clearing slots, or clearing the instance dict. */ + _PyObject_GC_UNTRACK(self); + } + /* + If we added a weaklist, we clear it. Do this *before* calling tp_del, + clearing slots, or clearing the instance dict. + + GC tracking must be off at this point. weakref callbacks (if any, and + whether directly here or indirectly in something we call) may trigger GC, + and if self is tracked at that point, it will look like trash to GC and GC + will try to delete self again. + */ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) PyObject_ClearWeakRefs(self); if (type->tp_del) { + _PyObject_GC_TRACK(self); type->tp_del(self); if (self->ob_refcnt > 0) { /* Resurrected */ goto endlabel; } + _PyObject_GC_UNTRACK(self); } if (has_finalizer) { - _PyObject_GC_UNTRACK(self); /* New weakrefs could be created during the finalizer call. If this occurs, clear them out without calling their finalizers since they might rely on part of the object -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:18 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:18 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328350=3A_String_constants_with_null_character_no_long?= =?utf-8?q?er_interned=2E?= Message-ID: <20161004152516.85797.29278.5FACF324@psf.io> https://hg.python.org/cpython/rev/8585b4de4fc0 changeset: 104277:8585b4de4fc0 branch: 3.6 parent: 104272:520cb70ecb90 parent: 104276:d7ab3241aef2 user: Serhiy Storchaka date: Tue Oct 04 18:21:25 2016 +0300 summary: Issue #28350: String constants with null character no longer interned. files: Lib/test/test_code.py | 20 +++++++++++++++++--- Misc/NEWS | 2 ++ Objects/codeobject.c | 16 ++++++++-------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -135,19 +135,27 @@ self.assertEqual(co.co_name, "funcname") self.assertEqual(co.co_firstlineno, 15) + +def isinterned(s): + return s is sys.intern(('_' + s + '_')[1:-1]) + class CodeConstsTest(unittest.TestCase): def find_const(self, consts, value): for v in consts: if v == value: return v - self.assertIn(value, consts) # rises an exception - self.fail('Should be never reached') + self.assertIn(value, consts) # raises an exception + self.fail('Should never be reached') def assertIsInterned(self, s): - if s is not sys.intern(s): + if not isinterned(s): self.fail('String %r is not interned' % (s,)) + def assertIsNotInterned(self, s): + if isinterned(s): + self.fail('String %r is interned' % (s,)) + @cpython_only def test_interned_string(self): co = compile('res = "str_value"', '?', 'exec') @@ -172,6 +180,12 @@ return a self.assertIsInterned(f()) + @cpython_only + def test_interned_string_with_null(self): + co = compile(r'res = "str\0value!"', '?', 'exec') + v = self.find_const(co.co_consts, 'str\0value!') + self.assertIsNotInterned(v) + class CodeWeakRefTest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28350: String constants with null character no longer interned. + - Issue #26617: Fix crash when GC runs during weakref callbacks. - Issue #27942: String constants now interned recursively in tuples and frozensets. diff --git a/Objects/codeobject.c b/Objects/codeobject.c --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -19,21 +19,21 @@ all_name_chars(PyObject *o) { static char ok_name_char[256]; - static unsigned char *name_chars = (unsigned char *)NAME_CHARS; - PyUnicodeObject *u = (PyUnicodeObject *)o; - const unsigned char *s; + static const unsigned char *name_chars = (unsigned char *)NAME_CHARS; + const unsigned char *s, *e; - if (!PyUnicode_Check(o) || PyUnicode_READY(u) == -1 || - PyUnicode_MAX_CHAR_VALUE(u) >= 128) + if (!PyUnicode_Check(o) || PyUnicode_READY(o) == -1 || + !PyUnicode_IS_ASCII(o)) return 0; if (ok_name_char[*name_chars] == 0) { - unsigned char *p; + const unsigned char *p; for (p = name_chars; *p; p++) ok_name_char[*p] = 1; } - s = PyUnicode_1BYTE_DATA(u); - while (*s) { + s = PyUnicode_1BYTE_DATA(o); + e = s + PyUnicode_GET_LENGTH(o); + while (s != e) { if (ok_name_char[*s++] == 0) return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:18 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161004152517.75730.48741.56E9346B@psf.io> https://hg.python.org/cpython/rev/549d9463c339 changeset: 104281:549d9463c339 parent: 104278:563d523036c6 parent: 104280:4368f897b33e user: Serhiy Storchaka date: Tue Oct 04 18:24:41 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 11:25:18 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 15:25:18 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzUw?= =?utf-8?q?=3A_String_constants_with_null_character_no_longer_interned=2E?= Message-ID: <20161004152516.82118.4902.6BE05969@psf.io> https://hg.python.org/cpython/rev/d7ab3241aef2 changeset: 104276:d7ab3241aef2 branch: 3.5 parent: 104260:b24d0f274623 user: Serhiy Storchaka date: Tue Oct 04 18:17:22 2016 +0300 summary: Issue #28350: String constants with null character no longer interned. files: Lib/test/test_code.py | 20 +++++++++++++++++--- Misc/NEWS | 2 ++ Objects/codeobject.c | 16 ++++++++-------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -135,19 +135,27 @@ self.assertEqual(co.co_name, "funcname") self.assertEqual(co.co_firstlineno, 15) + +def isinterned(s): + return s is sys.intern(('_' + s + '_')[1:-1]) + class CodeConstsTest(unittest.TestCase): def find_const(self, consts, value): for v in consts: if v == value: return v - self.assertIn(value, consts) # rises an exception - self.fail('Should be never reached') + self.assertIn(value, consts) # raises an exception + self.fail('Should never be reached') def assertIsInterned(self, s): - if s is not sys.intern(s): + if not isinterned(s): self.fail('String %r is not interned' % (s,)) + def assertIsNotInterned(self, s): + if isinterned(s): + self.fail('String %r is interned' % (s,)) + @cpython_only def test_interned_string(self): co = compile('res = "str_value"', '?', 'exec') @@ -172,6 +180,12 @@ return a self.assertIsInterned(f()) + @cpython_only + def test_interned_string_with_null(self): + co = compile(r'res = "str\0value!"', '?', 'exec') + v = self.find_const(co.co_consts, 'str\0value!') + self.assertIsNotInterned(v) + class CodeWeakRefTest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28350: String constants with null character no longer interned. + - Issue #27942: String constants now interned recursively in tuples and frozensets. - Issue #21578: Fixed misleading error message when ImportError called with diff --git a/Objects/codeobject.c b/Objects/codeobject.c --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -11,21 +11,21 @@ all_name_chars(PyObject *o) { static char ok_name_char[256]; - static unsigned char *name_chars = (unsigned char *)NAME_CHARS; - PyUnicodeObject *u = (PyUnicodeObject *)o; - const unsigned char *s; + static const unsigned char *name_chars = (unsigned char *)NAME_CHARS; + const unsigned char *s, *e; - if (!PyUnicode_Check(o) || PyUnicode_READY(u) == -1 || - PyUnicode_MAX_CHAR_VALUE(u) >= 128) + if (!PyUnicode_Check(o) || PyUnicode_READY(o) == -1 || + !PyUnicode_IS_ASCII(o)) return 0; if (ok_name_char[*name_chars] == 0) { - unsigned char *p; + const unsigned char *p; for (p = name_chars; *p; p++) ok_name_char[*p] = 1; } - s = PyUnicode_1BYTE_DATA(u); - while (*s) { + s = PyUnicode_1BYTE_DATA(o); + e = s + PyUnicode_GET_LENGTH(o); + while (s != e) { if (ok_name_char[*s++] == 0) return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 12:25:27 2016 From: python-checkins at python.org (steven.daprano) Date: Tue, 04 Oct 2016 16:25:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Automated_merge_with_ssh=3A//hg=2Epython=2Eorg/cpython?= Message-ID: <20161004162527.20873.10657.19DE33CD@psf.io> https://hg.python.org/cpython/rev/927e05b747d1 changeset: 104283:927e05b747d1 parent: 104281:549d9463c339 parent: 104282:9dce0e41bedd user: Steven D'Aprano date: Wed Oct 05 03:25:05 2016 +1100 summary: Automated merge with ssh://hg.python.org/cpython files: Doc/library/statistics.rst | 29 -- Lib/statistics.py | 269 +----------------------- Lib/test/test_statistics.py | 267 ----------------------- 3 files changed, 1 insertions(+), 564 deletions(-) diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -39,7 +39,6 @@ ======================= ============================================= :func:`mean` Arithmetic mean ("average") of data. -:func:`geometric_mean` Geometric mean of data. :func:`harmonic_mean` Harmonic mean of data. :func:`median` Median (middle value) of data. :func:`median_low` Low median of data. @@ -113,34 +112,6 @@ ``mean(data)`` is equivalent to calculating the true population mean ?. -.. function:: geometric_mean(data) - - Return the geometric mean of *data*, a sequence or iterator of - real-valued numbers. - - The geometric mean is the *n*-th root of the product of *n* data points. - It is a type of average, a measure of the central location of the data. - - The geometric mean is appropriate when averaging quantities which - are multiplied together rather than added, for example growth rates. - Suppose an investment grows by 10% in the first year, falls by 5% in - the second, then grows by 12% in the third, what is the average rate - of growth over the three years? - - .. doctest:: - - >>> geometric_mean([1.10, 0.95, 1.12]) - 1.0538483123382172 - - giving an average growth of 5.385%. Using the arithmetic mean will - give approximately 5.667%, which is too high. - - :exc:`StatisticsError` is raised if *data* is empty, or any - element is less than zero. - - .. versionadded:: 3.6 - - .. function:: harmonic_mean(data) Return the harmonic mean of *data*, a sequence or iterator of diff --git a/Lib/statistics.py b/Lib/statistics.py --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -11,7 +11,6 @@ Function Description ================== ============================================= mean Arithmetic mean (average) of data. -geometric_mean Geometric mean of data. harmonic_mean Harmonic mean of data. median Median (middle value) of data. median_low Low median of data. @@ -80,7 +79,7 @@ __all__ = [ 'StatisticsError', 'pstdev', 'pvariance', 'stdev', 'variance', 'median', 'median_low', 'median_high', 'median_grouped', - 'mean', 'mode', 'geometric_mean', 'harmonic_mean', + 'mean', 'mode', 'harmonic_mean', ] import collections @@ -287,229 +286,6 @@ yield x -class _nroot_NS: - """Hands off! Don't touch! - - Everything inside this namespace (class) is an even-more-private - implementation detail of the private _nth_root function. - """ - # This class exists only to be used as a namespace, for convenience - # of being able to keep the related functions together, and to - # collapse the group in an editor. If this were C# or C++, I would - # use a Namespace, but the closest Python has is a class. - # - # FIXME possibly move this out into a separate module? - # That feels like overkill, and may encourage people to treat it as - # a public feature. - def __init__(self): - raise TypeError('namespace only, do not instantiate') - - def nth_root(x, n): - """Return the positive nth root of numeric x. - - This may be more accurate than ** or pow(): - - >>> math.pow(1000, 1.0/3) #doctest:+SKIP - 9.999999999999998 - - >>> _nth_root(1000, 3) - 10.0 - >>> _nth_root(11**5, 5) - 11.0 - >>> _nth_root(2, 12) - 1.0594630943592953 - - """ - if not isinstance(n, int): - raise TypeError('degree n must be an int') - if n < 2: - raise ValueError('degree n must be 2 or more') - if isinstance(x, decimal.Decimal): - return _nroot_NS.decimal_nroot(x, n) - elif isinstance(x, numbers.Real): - return _nroot_NS.float_nroot(x, n) - else: - raise TypeError('expected a number, got %s') % type(x).__name__ - - def float_nroot(x, n): - """Handle nth root of Reals, treated as a float.""" - assert isinstance(n, int) and n > 1 - if x < 0: - raise ValueError('domain error: root of negative number') - elif x == 0: - return math.copysign(0.0, x) - elif x > 0: - try: - isinfinity = math.isinf(x) - except OverflowError: - return _nroot_NS.bignum_nroot(x, n) - else: - if isinfinity: - return float('inf') - else: - return _nroot_NS.nroot(x, n) - else: - assert math.isnan(x) - return float('nan') - - def nroot(x, n): - """Calculate x**(1/n), then improve the answer.""" - # This uses math.pow() to calculate an initial guess for the root, - # then uses the iterated nroot algorithm to improve it. - # - # By my testing, about 8% of the time the iterated algorithm ends - # up converging to a result which is less accurate than the initial - # guess. [FIXME: is this still true?] In that case, we use the - # guess instead of the "improved" value. This way, we're never - # less accurate than math.pow(). - r1 = math.pow(x, 1.0/n) - eps1 = abs(r1**n - x) - if eps1 == 0.0: - # r1 is the exact root, so we're done. By my testing, this - # occurs about 80% of the time for x < 1 and 30% of the - # time for x > 1. - return r1 - else: - try: - r2 = _nroot_NS.iterated_nroot(x, n, r1) - except RuntimeError: - return r1 - else: - eps2 = abs(r2**n - x) - if eps1 < eps2: - return r1 - return r2 - - def iterated_nroot(a, n, g): - """Return the nth root of a, starting with guess g. - - This is a special case of Newton's Method. - https://en.wikipedia.org/wiki/Nth_root_algorithm - """ - np = n - 1 - def iterate(r): - try: - return (np*r + a/math.pow(r, np))/n - except OverflowError: - # If r is large enough, r**np may overflow. If that - # happens, r**-np will be small, but not necessarily zero. - return (np*r + a*math.pow(r, -np))/n - # With a good guess, such as g = a**(1/n), this will converge in - # only a few iterations. However a poor guess can take thousands - # of iterations to converge, if at all. We guard against poor - # guesses by setting an upper limit to the number of iterations. - r1 = g - r2 = iterate(g) - for i in range(1000): - if r1 == r2: - break - # Use Floyd's cycle-finding algorithm to avoid being trapped - # in a cycle. - # https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare - r1 = iterate(r1) - r2 = iterate(iterate(r2)) - else: - # If the guess is particularly bad, the above may fail to - # converge in any reasonable time. - raise RuntimeError('nth-root failed to converge') - return r2 - - def decimal_nroot(x, n): - """Handle nth root of Decimals.""" - assert isinstance(x, decimal.Decimal) - assert isinstance(n, int) - if x.is_snan(): - # Signalling NANs always raise. - raise decimal.InvalidOperation('nth-root of snan') - if x.is_qnan(): - # Quiet NANs only raise if the context is set to raise, - # otherwise return a NAN. - ctx = decimal.getcontext() - if ctx.traps[decimal.InvalidOperation]: - raise decimal.InvalidOperation('nth-root of nan') - else: - # Preserve the input NAN. - return x - if x < 0: - raise ValueError('domain error: root of negative number') - if x.is_infinite(): - return x - # FIXME this hasn't had the extensive testing of the float - # version _iterated_nroot so there's possibly some buggy - # corner cases buried in here. Can it overflow? Fail to - # converge or get trapped in a cycle? Converge to a less - # accurate root? - np = n - 1 - def iterate(r): - return (np*r + x/r**np)/n - r0 = x**(decimal.Decimal(1)/n) - assert isinstance(r0, decimal.Decimal) - r1 = iterate(r0) - while True: - if r1 == r0: - return r1 - r0, r1 = r1, iterate(r1) - - def bignum_nroot(x, n): - """Return the nth root of a positive huge number.""" - assert x > 0 - # I state without proof that ??x ? ??2???(x//2) - # and that for sufficiently big x the error is acceptable. - # We now halve x until it is small enough to get the root. - m = 0 - while True: - x //= 2 - m += 1 - try: - y = float(x) - except OverflowError: - continue - break - a = _nroot_NS.nroot(y, n) - # At this point, we want the nth-root of 2**m, or 2**(m/n). - # We can write that as 2**(q + r/n) = 2**q * ??2**r where q = m//n. - q, r = divmod(m, n) - b = 2**q * _nroot_NS.nroot(2**r, n) - return a * b - - -# This is the (private) function for calculating nth roots: -_nth_root = _nroot_NS.nth_root -assert type(_nth_root) is type(lambda: None) - - -def _product(values): - """Return product of values as (exponent, mantissa).""" - errmsg = 'mixed Decimal and float is not supported' - prod = 1 - for x in values: - if isinstance(x, float): - break - prod *= x - else: - return (0, prod) - if isinstance(prod, Decimal): - raise TypeError(errmsg) - # Since floats can overflow easily, we calculate the product as a - # sort of poor-man's BigFloat. Given that: - # - # x = 2**p * m # p == power or exponent (scale), m = mantissa - # - # we can calculate the product of two (or more) x values as: - # - # x1*x2 = 2**p1*m1 * 2**p2*m2 = 2**(p1+p2)*(m1*m2) - # - mant, scale = 1, 0 #math.frexp(prod) # FIXME - for y in chain([x], values): - if isinstance(y, Decimal): - raise TypeError(errmsg) - m1, e1 = math.frexp(y) - m2, e2 = math.frexp(mant) - scale += (e1 + e2) - mant = m1*m2 - return (scale, mant) - - # === Measures of central tendency (averages) === def mean(data): @@ -538,49 +314,6 @@ return _convert(total/n, T) -def geometric_mean(data): - """Return the geometric mean of data. - - The geometric mean is appropriate when averaging quantities which - are multiplied together rather than added, for example growth rates. - Suppose an investment grows by 10% in the first year, falls by 5% in - the second, then grows by 12% in the third, what is the average rate - of growth over the three years? - - >>> geometric_mean([1.10, 0.95, 1.12]) - 1.0538483123382172 - - giving an average growth of 5.385%. Using the arithmetic mean will - give approximately 5.667%, which is too high. - - ``StatisticsError`` will be raised if ``data`` is empty, or any - element is less than zero. - """ - if iter(data) is data: - data = list(data) - errmsg = 'geometric mean does not support negative values' - n = len(data) - if n < 1: - raise StatisticsError('geometric_mean requires at least one data point') - elif n == 1: - x = data[0] - if isinstance(g, (numbers.Real, Decimal)): - if x < 0: - raise StatisticsError(errmsg) - return x - else: - raise TypeError('unsupported type') - else: - scale, prod = _product(_fail_neg(data, errmsg)) - r = _nth_root(prod, n) - if scale: - p, q = divmod(scale, n) - s = 2**p * _nth_root(2**q, n) - else: - s = 1 - return s*r - - def harmonic_mean(data): """Return the harmonic mean of data. diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1010,273 +1010,6 @@ self.assertEqual(errmsg, msg) -class Test_Product(NumericTestCase): - """Test the private _product function.""" - - def test_ints(self): - data = [1, 2, 5, 7, 9] - self.assertEqual(statistics._product(data), (0, 630)) - self.assertEqual(statistics._product(data*100), (0, 630**100)) - - def test_floats(self): - data = [1.0, 2.0, 4.0, 8.0] - self.assertEqual(statistics._product(data), (8, 0.25)) - - def test_overflow(self): - # Test with floats that overflow. - data = [1e300]*5 - self.assertEqual(statistics._product(data), (5980, 0.6928287951283193)) - - def test_fractions(self): - F = Fraction - data = [F(14, 23), F(69, 1), F(665, 529), F(299, 105), F(1683, 39)] - exp, mant = statistics._product(data) - self.assertEqual(exp, 0) - self.assertEqual(mant, F(2*3*7*11*17*19, 23)) - self.assertTrue(isinstance(mant, F)) - # Mixed Fraction and int. - data = [3, 25, F(2, 15)] - exp, mant = statistics._product(data) - self.assertEqual(exp, 0) - self.assertEqual(mant, F(10)) - self.assertTrue(isinstance(mant, F)) - - def test_decimal(self): - D = Decimal - data = [D('24.5'), D('17.6'), D('0.025'), D('1.3')] - expected = D('14.014000') - self.assertEqual(statistics._product(data), (0, expected)) - - def test_mixed_decimal_float(self): - # Test that mixed Decimal and float raises. - self.assertRaises(TypeError, statistics._product, [1.0, Decimal(1)]) - self.assertRaises(TypeError, statistics._product, [Decimal(1), 1.0]) - - - at unittest.skipIf(True, "FIXME: tests known to fail, see issue #27181") -class Test_Nth_Root(NumericTestCase): - """Test the functionality of the private _nth_root function.""" - - def setUp(self): - self.nroot = statistics._nth_root - - # --- Special values (infinities, NANs, zeroes) --- - - def test_float_NAN(self): - # Test that the root of a float NAN is a float NAN. - NAN = float('nan') - for n in range(2, 9): - with self.subTest(n=n): - result = self.nroot(NAN, n) - self.assertTrue(math.isnan(result)) - - def test_decimal_QNAN(self): - # Test the behaviour when taking the root of a Decimal quiet NAN. - NAN = decimal.Decimal('nan') - with decimal.localcontext() as ctx: - ctx.traps[decimal.InvalidOperation] = 1 - self.assertRaises(decimal.InvalidOperation, self.nroot, NAN, 5) - ctx.traps[decimal.InvalidOperation] = 0 - self.assertTrue(self.nroot(NAN, 5).is_qnan()) - - def test_decimal_SNAN(self): - # Test that taking the root of a Decimal sNAN always raises. - sNAN = decimal.Decimal('snan') - with decimal.localcontext() as ctx: - ctx.traps[decimal.InvalidOperation] = 1 - self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) - ctx.traps[decimal.InvalidOperation] = 0 - self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) - - def test_inf(self): - # Test that the root of infinity is infinity. - for INF in (float('inf'), decimal.Decimal('inf')): - for n in range(2, 9): - with self.subTest(n=n, inf=INF): - self.assertEqual(self.nroot(INF, n), INF) - - # FIXME: need to check Decimal zeroes too. - def test_zero(self): - # Test that the root of +0.0 is +0.0. - for n in range(2, 11): - with self.subTest(n=n): - result = self.nroot(+0.0, n) - self.assertEqual(result, 0.0) - self.assertEqual(sign(result), +1) - - # FIXME: need to check Decimal zeroes too. - def test_neg_zero(self): - # Test that the root of -0.0 is -0.0. - for n in range(2, 11): - with self.subTest(n=n): - result = self.nroot(-0.0, n) - self.assertEqual(result, 0.0) - self.assertEqual(sign(result), -1) - - # --- Test return types --- - - def check_result_type(self, x, n, outtype): - self.assertIsInstance(self.nroot(x, n), outtype) - class MySubclass(type(x)): - pass - self.assertIsInstance(self.nroot(MySubclass(x), n), outtype) - - def testDecimal(self): - # Test that Decimal arguments return Decimal results. - self.check_result_type(decimal.Decimal('33.3'), 3, decimal.Decimal) - - def testFloat(self): - # Test that other arguments return float results. - for x in (0.2, Fraction(11, 7), 91): - self.check_result_type(x, 6, float) - - # --- Test bad input --- - - def testBadOrderTypes(self): - # Test that nroot raises correctly when n has the wrong type. - for n in (5.0, 2j, None, 'x', b'x', [], {}, set(), sign): - with self.subTest(n=n): - self.assertRaises(TypeError, self.nroot, 2.5, n) - - def testBadOrderValues(self): - # Test that nroot raises correctly when n has a wrong value. - for n in (1, 0, -1, -2, -87): - with self.subTest(n=n): - self.assertRaises(ValueError, self.nroot, 2.5, n) - - def testBadTypes(self): - # Test that nroot raises correctly when x has the wrong type. - for x in (None, 'x', b'x', [], {}, set(), sign): - with self.subTest(x=x): - self.assertRaises(TypeError, self.nroot, x, 3) - - def testNegativeError(self): - # Test negative x raises correctly. - x = random.uniform(-20.0, -0.1) - assert x < 0 - for n in range(3, 7): - with self.subTest(x=x, n=n): - self.assertRaises(ValueError, self.nroot, x, n) - # And Decimal. - self.assertRaises(ValueError, self.nroot, Decimal(-27), 3) - - # --- Test that nroot is never worse than calling math.pow() --- - - def check_error_is_no_worse(self, x, n): - y = math.pow(x, n) - with self.subTest(x=x, n=n, y=y): - err1 = abs(self.nroot(y, n) - x) - err2 = abs(math.pow(y, 1.0/n) - x) - self.assertLessEqual(err1, err2) - - def testCompareWithPowSmall(self): - # Compare nroot with pow for small values of x. - for i in range(200): - x = random.uniform(1e-9, 1.0-1e-9) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowMedium(self): - # Compare nroot with pow for medium-sized values of x. - for i in range(200): - x = random.uniform(1.0, 100.0) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowLarge(self): - # Compare nroot with pow for largish values of x. - for i in range(200): - x = random.uniform(100.0, 10000.0) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowHuge(self): - # Compare nroot with pow for huge values of x. - for i in range(200): - x = random.uniform(1e20, 1e50) - # We restrict the order here to avoid an Overflow error. - n = random.choice(range(2, 7)) - self.check_error_is_no_worse(x, n) - - # --- Test for numerically correct answers --- - - def testExactPowers(self): - # Test that small integer powers are calculated exactly. - for i in range(1, 51): - for n in range(2, 16): - if (i, n) == (35, 13): - # See testExpectedFailure35p13 - continue - with self.subTest(i=i, n=n): - x = i**n - self.assertEqual(self.nroot(x, n), i) - - def testExpectedFailure35p13(self): - # Test the expected failure 35**13 is almost exact. - x = 35**13 - err = abs(self.nroot(x, 13) - 35) - self.assertLessEqual(err, 0.000000001) - - def testOne(self): - # Test that the root of 1.0 is 1.0. - for n in range(2, 11): - with self.subTest(n=n): - self.assertEqual(self.nroot(1.0, n), 1.0) - - def testFraction(self): - # Test Fraction results. - x = Fraction(89, 75) - self.assertEqual(self.nroot(x**12, 12), float(x)) - - def testInt(self): - # Test int results. - x = 276 - self.assertEqual(self.nroot(x**24, 24), x) - - def testBigInt(self): - # Test that ints too big to convert to floats work. - bignum = 10**20 # That's not that big... - self.assertEqual(self.nroot(bignum**280, 280), bignum) - # Can we make it bigger? - hugenum = bignum**50 - # Make sure that it is too big to convert to a float. - try: - y = float(hugenum) - except OverflowError: - pass - else: - raise AssertionError('hugenum is not big enough') - self.assertEqual(self.nroot(hugenum, 50), float(bignum)) - - def testDecimal(self): - # Test Decimal results. - for s in '3.759 64.027 5234.338'.split(): - x = decimal.Decimal(s) - with self.subTest(x=x): - a = self.nroot(x**5, 5) - self.assertEqual(a, x) - a = self.nroot(x**17, 17) - self.assertEqual(a, x) - - def testFloat(self): - # Test float results. - for x in (3.04e-16, 18.25, 461.3, 1.9e17): - with self.subTest(x=x): - self.assertEqual(self.nroot(x**3, 3), x) - self.assertEqual(self.nroot(x**8, 8), x) - self.assertEqual(self.nroot(x**11, 11), x) - - -class Test_NthRoot_NS(unittest.TestCase): - """Test internals of the nth_root function, hidden in _nroot_NS.""" - - def test_class_cannot_be_instantiated(self): - # Test that _nroot_NS cannot be instantiated. - # It should be a namespace, like in C++ or C#, but Python - # lacks that feature and so we have to make do with a class. - self.assertRaises(TypeError, statistics._nroot_NS) - - # === Tests for public functions === class UnivariateCommonMixin: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 12:25:27 2016 From: python-checkins at python.org (steven.daprano) Date: Tue, 04 Oct 2016 16:25:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2327181_remove_geom?= =?utf-8?q?etric=5Fmean_and_defer_for_3=2E7=2E?= Message-ID: <20161004162526.79532.76784.3E76792E@psf.io> https://hg.python.org/cpython/rev/9dce0e41bedd changeset: 104282:9dce0e41bedd parent: 104274:3fed30fa37f4 user: Steven D'Aprano date: Wed Oct 05 03:24:45 2016 +1100 summary: Issue #27181 remove geometric_mean and defer for 3.7. files: Doc/library/statistics.rst | 29 -- Lib/statistics.py | 269 +----------------------- Lib/test/test_statistics.py | 267 ----------------------- 3 files changed, 1 insertions(+), 564 deletions(-) diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -39,7 +39,6 @@ ======================= ============================================= :func:`mean` Arithmetic mean ("average") of data. -:func:`geometric_mean` Geometric mean of data. :func:`harmonic_mean` Harmonic mean of data. :func:`median` Median (middle value) of data. :func:`median_low` Low median of data. @@ -113,34 +112,6 @@ ``mean(data)`` is equivalent to calculating the true population mean ?. -.. function:: geometric_mean(data) - - Return the geometric mean of *data*, a sequence or iterator of - real-valued numbers. - - The geometric mean is the *n*-th root of the product of *n* data points. - It is a type of average, a measure of the central location of the data. - - The geometric mean is appropriate when averaging quantities which - are multiplied together rather than added, for example growth rates. - Suppose an investment grows by 10% in the first year, falls by 5% in - the second, then grows by 12% in the third, what is the average rate - of growth over the three years? - - .. doctest:: - - >>> geometric_mean([1.10, 0.95, 1.12]) - 1.0538483123382172 - - giving an average growth of 5.385%. Using the arithmetic mean will - give approximately 5.667%, which is too high. - - :exc:`StatisticsError` is raised if *data* is empty, or any - element is less than zero. - - .. versionadded:: 3.6 - - .. function:: harmonic_mean(data) Return the harmonic mean of *data*, a sequence or iterator of diff --git a/Lib/statistics.py b/Lib/statistics.py --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -11,7 +11,6 @@ Function Description ================== ============================================= mean Arithmetic mean (average) of data. -geometric_mean Geometric mean of data. harmonic_mean Harmonic mean of data. median Median (middle value) of data. median_low Low median of data. @@ -80,7 +79,7 @@ __all__ = [ 'StatisticsError', 'pstdev', 'pvariance', 'stdev', 'variance', 'median', 'median_low', 'median_high', 'median_grouped', - 'mean', 'mode', 'geometric_mean', 'harmonic_mean', + 'mean', 'mode', 'harmonic_mean', ] import collections @@ -287,229 +286,6 @@ yield x -class _nroot_NS: - """Hands off! Don't touch! - - Everything inside this namespace (class) is an even-more-private - implementation detail of the private _nth_root function. - """ - # This class exists only to be used as a namespace, for convenience - # of being able to keep the related functions together, and to - # collapse the group in an editor. If this were C# or C++, I would - # use a Namespace, but the closest Python has is a class. - # - # FIXME possibly move this out into a separate module? - # That feels like overkill, and may encourage people to treat it as - # a public feature. - def __init__(self): - raise TypeError('namespace only, do not instantiate') - - def nth_root(x, n): - """Return the positive nth root of numeric x. - - This may be more accurate than ** or pow(): - - >>> math.pow(1000, 1.0/3) #doctest:+SKIP - 9.999999999999998 - - >>> _nth_root(1000, 3) - 10.0 - >>> _nth_root(11**5, 5) - 11.0 - >>> _nth_root(2, 12) - 1.0594630943592953 - - """ - if not isinstance(n, int): - raise TypeError('degree n must be an int') - if n < 2: - raise ValueError('degree n must be 2 or more') - if isinstance(x, decimal.Decimal): - return _nroot_NS.decimal_nroot(x, n) - elif isinstance(x, numbers.Real): - return _nroot_NS.float_nroot(x, n) - else: - raise TypeError('expected a number, got %s') % type(x).__name__ - - def float_nroot(x, n): - """Handle nth root of Reals, treated as a float.""" - assert isinstance(n, int) and n > 1 - if x < 0: - raise ValueError('domain error: root of negative number') - elif x == 0: - return math.copysign(0.0, x) - elif x > 0: - try: - isinfinity = math.isinf(x) - except OverflowError: - return _nroot_NS.bignum_nroot(x, n) - else: - if isinfinity: - return float('inf') - else: - return _nroot_NS.nroot(x, n) - else: - assert math.isnan(x) - return float('nan') - - def nroot(x, n): - """Calculate x**(1/n), then improve the answer.""" - # This uses math.pow() to calculate an initial guess for the root, - # then uses the iterated nroot algorithm to improve it. - # - # By my testing, about 8% of the time the iterated algorithm ends - # up converging to a result which is less accurate than the initial - # guess. [FIXME: is this still true?] In that case, we use the - # guess instead of the "improved" value. This way, we're never - # less accurate than math.pow(). - r1 = math.pow(x, 1.0/n) - eps1 = abs(r1**n - x) - if eps1 == 0.0: - # r1 is the exact root, so we're done. By my testing, this - # occurs about 80% of the time for x < 1 and 30% of the - # time for x > 1. - return r1 - else: - try: - r2 = _nroot_NS.iterated_nroot(x, n, r1) - except RuntimeError: - return r1 - else: - eps2 = abs(r2**n - x) - if eps1 < eps2: - return r1 - return r2 - - def iterated_nroot(a, n, g): - """Return the nth root of a, starting with guess g. - - This is a special case of Newton's Method. - https://en.wikipedia.org/wiki/Nth_root_algorithm - """ - np = n - 1 - def iterate(r): - try: - return (np*r + a/math.pow(r, np))/n - except OverflowError: - # If r is large enough, r**np may overflow. If that - # happens, r**-np will be small, but not necessarily zero. - return (np*r + a*math.pow(r, -np))/n - # With a good guess, such as g = a**(1/n), this will converge in - # only a few iterations. However a poor guess can take thousands - # of iterations to converge, if at all. We guard against poor - # guesses by setting an upper limit to the number of iterations. - r1 = g - r2 = iterate(g) - for i in range(1000): - if r1 == r2: - break - # Use Floyd's cycle-finding algorithm to avoid being trapped - # in a cycle. - # https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare - r1 = iterate(r1) - r2 = iterate(iterate(r2)) - else: - # If the guess is particularly bad, the above may fail to - # converge in any reasonable time. - raise RuntimeError('nth-root failed to converge') - return r2 - - def decimal_nroot(x, n): - """Handle nth root of Decimals.""" - assert isinstance(x, decimal.Decimal) - assert isinstance(n, int) - if x.is_snan(): - # Signalling NANs always raise. - raise decimal.InvalidOperation('nth-root of snan') - if x.is_qnan(): - # Quiet NANs only raise if the context is set to raise, - # otherwise return a NAN. - ctx = decimal.getcontext() - if ctx.traps[decimal.InvalidOperation]: - raise decimal.InvalidOperation('nth-root of nan') - else: - # Preserve the input NAN. - return x - if x < 0: - raise ValueError('domain error: root of negative number') - if x.is_infinite(): - return x - # FIXME this hasn't had the extensive testing of the float - # version _iterated_nroot so there's possibly some buggy - # corner cases buried in here. Can it overflow? Fail to - # converge or get trapped in a cycle? Converge to a less - # accurate root? - np = n - 1 - def iterate(r): - return (np*r + x/r**np)/n - r0 = x**(decimal.Decimal(1)/n) - assert isinstance(r0, decimal.Decimal) - r1 = iterate(r0) - while True: - if r1 == r0: - return r1 - r0, r1 = r1, iterate(r1) - - def bignum_nroot(x, n): - """Return the nth root of a positive huge number.""" - assert x > 0 - # I state without proof that ??x ? ??2???(x//2) - # and that for sufficiently big x the error is acceptable. - # We now halve x until it is small enough to get the root. - m = 0 - while True: - x //= 2 - m += 1 - try: - y = float(x) - except OverflowError: - continue - break - a = _nroot_NS.nroot(y, n) - # At this point, we want the nth-root of 2**m, or 2**(m/n). - # We can write that as 2**(q + r/n) = 2**q * ??2**r where q = m//n. - q, r = divmod(m, n) - b = 2**q * _nroot_NS.nroot(2**r, n) - return a * b - - -# This is the (private) function for calculating nth roots: -_nth_root = _nroot_NS.nth_root -assert type(_nth_root) is type(lambda: None) - - -def _product(values): - """Return product of values as (exponent, mantissa).""" - errmsg = 'mixed Decimal and float is not supported' - prod = 1 - for x in values: - if isinstance(x, float): - break - prod *= x - else: - return (0, prod) - if isinstance(prod, Decimal): - raise TypeError(errmsg) - # Since floats can overflow easily, we calculate the product as a - # sort of poor-man's BigFloat. Given that: - # - # x = 2**p * m # p == power or exponent (scale), m = mantissa - # - # we can calculate the product of two (or more) x values as: - # - # x1*x2 = 2**p1*m1 * 2**p2*m2 = 2**(p1+p2)*(m1*m2) - # - mant, scale = 1, 0 #math.frexp(prod) # FIXME - for y in chain([x], values): - if isinstance(y, Decimal): - raise TypeError(errmsg) - m1, e1 = math.frexp(y) - m2, e2 = math.frexp(mant) - scale += (e1 + e2) - mant = m1*m2 - return (scale, mant) - - # === Measures of central tendency (averages) === def mean(data): @@ -538,49 +314,6 @@ return _convert(total/n, T) -def geometric_mean(data): - """Return the geometric mean of data. - - The geometric mean is appropriate when averaging quantities which - are multiplied together rather than added, for example growth rates. - Suppose an investment grows by 10% in the first year, falls by 5% in - the second, then grows by 12% in the third, what is the average rate - of growth over the three years? - - >>> geometric_mean([1.10, 0.95, 1.12]) - 1.0538483123382172 - - giving an average growth of 5.385%. Using the arithmetic mean will - give approximately 5.667%, which is too high. - - ``StatisticsError`` will be raised if ``data`` is empty, or any - element is less than zero. - """ - if iter(data) is data: - data = list(data) - errmsg = 'geometric mean does not support negative values' - n = len(data) - if n < 1: - raise StatisticsError('geometric_mean requires at least one data point') - elif n == 1: - x = data[0] - if isinstance(g, (numbers.Real, Decimal)): - if x < 0: - raise StatisticsError(errmsg) - return x - else: - raise TypeError('unsupported type') - else: - scale, prod = _product(_fail_neg(data, errmsg)) - r = _nth_root(prod, n) - if scale: - p, q = divmod(scale, n) - s = 2**p * _nth_root(2**q, n) - else: - s = 1 - return s*r - - def harmonic_mean(data): """Return the harmonic mean of data. diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1010,273 +1010,6 @@ self.assertEqual(errmsg, msg) -class Test_Product(NumericTestCase): - """Test the private _product function.""" - - def test_ints(self): - data = [1, 2, 5, 7, 9] - self.assertEqual(statistics._product(data), (0, 630)) - self.assertEqual(statistics._product(data*100), (0, 630**100)) - - def test_floats(self): - data = [1.0, 2.0, 4.0, 8.0] - self.assertEqual(statistics._product(data), (8, 0.25)) - - def test_overflow(self): - # Test with floats that overflow. - data = [1e300]*5 - self.assertEqual(statistics._product(data), (5980, 0.6928287951283193)) - - def test_fractions(self): - F = Fraction - data = [F(14, 23), F(69, 1), F(665, 529), F(299, 105), F(1683, 39)] - exp, mant = statistics._product(data) - self.assertEqual(exp, 0) - self.assertEqual(mant, F(2*3*7*11*17*19, 23)) - self.assertTrue(isinstance(mant, F)) - # Mixed Fraction and int. - data = [3, 25, F(2, 15)] - exp, mant = statistics._product(data) - self.assertEqual(exp, 0) - self.assertEqual(mant, F(10)) - self.assertTrue(isinstance(mant, F)) - - def test_decimal(self): - D = Decimal - data = [D('24.5'), D('17.6'), D('0.025'), D('1.3')] - expected = D('14.014000') - self.assertEqual(statistics._product(data), (0, expected)) - - def test_mixed_decimal_float(self): - # Test that mixed Decimal and float raises. - self.assertRaises(TypeError, statistics._product, [1.0, Decimal(1)]) - self.assertRaises(TypeError, statistics._product, [Decimal(1), 1.0]) - - - at unittest.skipIf(True, "FIXME: tests known to fail, see issue #27181") -class Test_Nth_Root(NumericTestCase): - """Test the functionality of the private _nth_root function.""" - - def setUp(self): - self.nroot = statistics._nth_root - - # --- Special values (infinities, NANs, zeroes) --- - - def test_float_NAN(self): - # Test that the root of a float NAN is a float NAN. - NAN = float('nan') - for n in range(2, 9): - with self.subTest(n=n): - result = self.nroot(NAN, n) - self.assertTrue(math.isnan(result)) - - def test_decimal_QNAN(self): - # Test the behaviour when taking the root of a Decimal quiet NAN. - NAN = decimal.Decimal('nan') - with decimal.localcontext() as ctx: - ctx.traps[decimal.InvalidOperation] = 1 - self.assertRaises(decimal.InvalidOperation, self.nroot, NAN, 5) - ctx.traps[decimal.InvalidOperation] = 0 - self.assertTrue(self.nroot(NAN, 5).is_qnan()) - - def test_decimal_SNAN(self): - # Test that taking the root of a Decimal sNAN always raises. - sNAN = decimal.Decimal('snan') - with decimal.localcontext() as ctx: - ctx.traps[decimal.InvalidOperation] = 1 - self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) - ctx.traps[decimal.InvalidOperation] = 0 - self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) - - def test_inf(self): - # Test that the root of infinity is infinity. - for INF in (float('inf'), decimal.Decimal('inf')): - for n in range(2, 9): - with self.subTest(n=n, inf=INF): - self.assertEqual(self.nroot(INF, n), INF) - - # FIXME: need to check Decimal zeroes too. - def test_zero(self): - # Test that the root of +0.0 is +0.0. - for n in range(2, 11): - with self.subTest(n=n): - result = self.nroot(+0.0, n) - self.assertEqual(result, 0.0) - self.assertEqual(sign(result), +1) - - # FIXME: need to check Decimal zeroes too. - def test_neg_zero(self): - # Test that the root of -0.0 is -0.0. - for n in range(2, 11): - with self.subTest(n=n): - result = self.nroot(-0.0, n) - self.assertEqual(result, 0.0) - self.assertEqual(sign(result), -1) - - # --- Test return types --- - - def check_result_type(self, x, n, outtype): - self.assertIsInstance(self.nroot(x, n), outtype) - class MySubclass(type(x)): - pass - self.assertIsInstance(self.nroot(MySubclass(x), n), outtype) - - def testDecimal(self): - # Test that Decimal arguments return Decimal results. - self.check_result_type(decimal.Decimal('33.3'), 3, decimal.Decimal) - - def testFloat(self): - # Test that other arguments return float results. - for x in (0.2, Fraction(11, 7), 91): - self.check_result_type(x, 6, float) - - # --- Test bad input --- - - def testBadOrderTypes(self): - # Test that nroot raises correctly when n has the wrong type. - for n in (5.0, 2j, None, 'x', b'x', [], {}, set(), sign): - with self.subTest(n=n): - self.assertRaises(TypeError, self.nroot, 2.5, n) - - def testBadOrderValues(self): - # Test that nroot raises correctly when n has a wrong value. - for n in (1, 0, -1, -2, -87): - with self.subTest(n=n): - self.assertRaises(ValueError, self.nroot, 2.5, n) - - def testBadTypes(self): - # Test that nroot raises correctly when x has the wrong type. - for x in (None, 'x', b'x', [], {}, set(), sign): - with self.subTest(x=x): - self.assertRaises(TypeError, self.nroot, x, 3) - - def testNegativeError(self): - # Test negative x raises correctly. - x = random.uniform(-20.0, -0.1) - assert x < 0 - for n in range(3, 7): - with self.subTest(x=x, n=n): - self.assertRaises(ValueError, self.nroot, x, n) - # And Decimal. - self.assertRaises(ValueError, self.nroot, Decimal(-27), 3) - - # --- Test that nroot is never worse than calling math.pow() --- - - def check_error_is_no_worse(self, x, n): - y = math.pow(x, n) - with self.subTest(x=x, n=n, y=y): - err1 = abs(self.nroot(y, n) - x) - err2 = abs(math.pow(y, 1.0/n) - x) - self.assertLessEqual(err1, err2) - - def testCompareWithPowSmall(self): - # Compare nroot with pow for small values of x. - for i in range(200): - x = random.uniform(1e-9, 1.0-1e-9) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowMedium(self): - # Compare nroot with pow for medium-sized values of x. - for i in range(200): - x = random.uniform(1.0, 100.0) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowLarge(self): - # Compare nroot with pow for largish values of x. - for i in range(200): - x = random.uniform(100.0, 10000.0) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowHuge(self): - # Compare nroot with pow for huge values of x. - for i in range(200): - x = random.uniform(1e20, 1e50) - # We restrict the order here to avoid an Overflow error. - n = random.choice(range(2, 7)) - self.check_error_is_no_worse(x, n) - - # --- Test for numerically correct answers --- - - def testExactPowers(self): - # Test that small integer powers are calculated exactly. - for i in range(1, 51): - for n in range(2, 16): - if (i, n) == (35, 13): - # See testExpectedFailure35p13 - continue - with self.subTest(i=i, n=n): - x = i**n - self.assertEqual(self.nroot(x, n), i) - - def testExpectedFailure35p13(self): - # Test the expected failure 35**13 is almost exact. - x = 35**13 - err = abs(self.nroot(x, 13) - 35) - self.assertLessEqual(err, 0.000000001) - - def testOne(self): - # Test that the root of 1.0 is 1.0. - for n in range(2, 11): - with self.subTest(n=n): - self.assertEqual(self.nroot(1.0, n), 1.0) - - def testFraction(self): - # Test Fraction results. - x = Fraction(89, 75) - self.assertEqual(self.nroot(x**12, 12), float(x)) - - def testInt(self): - # Test int results. - x = 276 - self.assertEqual(self.nroot(x**24, 24), x) - - def testBigInt(self): - # Test that ints too big to convert to floats work. - bignum = 10**20 # That's not that big... - self.assertEqual(self.nroot(bignum**280, 280), bignum) - # Can we make it bigger? - hugenum = bignum**50 - # Make sure that it is too big to convert to a float. - try: - y = float(hugenum) - except OverflowError: - pass - else: - raise AssertionError('hugenum is not big enough') - self.assertEqual(self.nroot(hugenum, 50), float(bignum)) - - def testDecimal(self): - # Test Decimal results. - for s in '3.759 64.027 5234.338'.split(): - x = decimal.Decimal(s) - with self.subTest(x=x): - a = self.nroot(x**5, 5) - self.assertEqual(a, x) - a = self.nroot(x**17, 17) - self.assertEqual(a, x) - - def testFloat(self): - # Test float results. - for x in (3.04e-16, 18.25, 461.3, 1.9e17): - with self.subTest(x=x): - self.assertEqual(self.nroot(x**3, 3), x) - self.assertEqual(self.nroot(x**8, 8), x) - self.assertEqual(self.nroot(x**11, 11), x) - - -class Test_NthRoot_NS(unittest.TestCase): - """Test internals of the nth_root function, hidden in _nroot_NS.""" - - def test_class_cannot_be_instantiated(self): - # Test that _nroot_NS cannot be instantiated. - # It should be a namespace, like in C++ or C#, but Python - # lacks that feature and so we have to make do with a class. - self.assertRaises(TypeError, statistics._nroot_NS) - - # === Tests for public functions === class UnivariateCommonMixin: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:09:37 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 17:09:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328321=3A_Fixed_writing_non-BMP_characters_with_binary?= =?utf-8?q?_format_in_plistlib=2E?= Message-ID: <20161004170937.20667.82802.727AA2AC@psf.io> https://hg.python.org/cpython/rev/3a7234d04fe9 changeset: 104285:3a7234d04fe9 branch: 3.6 parent: 104280:4368f897b33e parent: 104284:381ef0f08f89 user: Serhiy Storchaka date: Tue Oct 04 20:08:29 2016 +0300 summary: Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. files: Lib/plistlib.py | 2 +- Lib/test/test_plistlib.py | 7 +++++++ Misc/NEWS | 2 ++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/plistlib.py b/Lib/plistlib.py --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -918,7 +918,7 @@ self._write_size(0x50, len(value)) except UnicodeEncodeError: t = value.encode('utf-16be') - self._write_size(0x60, len(value)) + self._write_size(0x60, len(t) // 2) self._fp.write(t) diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -360,6 +360,13 @@ plistlib.dumps, testString) + def test_non_bmp_characters(self): + pl = {'python': '\U0001f40d'} + for fmt in ALL_FORMATS: + with self.subTest(fmt=fmt): + data = plistlib.dumps(pl, fmt=fmt) + self.assertEqual(plistlib.loads(data), pl) + def test_nondictroot(self): for fmt in ALL_FORMATS: with self.subTest(fmt=fmt): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,8 @@ Library ------- +- Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. + - Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. - Issue #28227: gzip now supports pathlib. Patch by Ethan Furman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:09:37 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 17:09:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzIx?= =?utf-8?q?=3A_Fixed_writing_non-BMP_characters_with_binary_format_in_plis?= =?utf-8?q?tlib=2E?= Message-ID: <20161004170937.82256.63221.7F9F7D29@psf.io> https://hg.python.org/cpython/rev/381ef0f08f89 changeset: 104284:381ef0f08f89 branch: 3.5 parent: 104279:b674fd340a23 user: Serhiy Storchaka date: Tue Oct 04 20:04:30 2016 +0300 summary: Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. files: Lib/plistlib.py | 2 +- Lib/test/test_plistlib.py | 7 +++++++ Misc/NEWS | 2 ++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/plistlib.py b/Lib/plistlib.py --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -918,7 +918,7 @@ self._write_size(0x50, len(value)) except UnicodeEncodeError: t = value.encode('utf-16be') - self._write_size(0x60, len(value)) + self._write_size(0x60, len(t) // 2) self._fp.write(t) diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -361,6 +361,13 @@ plistlib.dumps, testString) + def test_non_bmp_characters(self): + pl = {'python': '\U0001f40d'} + for fmt in ALL_FORMATS: + with self.subTest(fmt=fmt): + data = plistlib.dumps(pl, fmt=fmt) + self.assertEqual(plistlib.loads(data), pl) + def test_nondictroot(self): for fmt in ALL_FORMATS: with self.subTest(fmt=fmt): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -89,6 +89,8 @@ Library ------- +- Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. + - Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:09:38 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 04 Oct 2016 17:09:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328321=3A_Fixed_writing_non-BMP_characters_with_?= =?utf-8?q?binary_format_in_plistlib=2E?= Message-ID: <20161004170937.20667.73145.45B5E83F@psf.io> https://hg.python.org/cpython/rev/b6c85e7e558a changeset: 104286:b6c85e7e558a parent: 104283:927e05b747d1 parent: 104285:3a7234d04fe9 user: Serhiy Storchaka date: Tue Oct 04 20:08:59 2016 +0300 summary: Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. files: Lib/plistlib.py | 2 +- Lib/test/test_plistlib.py | 7 +++++++ Misc/NEWS | 2 ++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/plistlib.py b/Lib/plistlib.py --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -918,7 +918,7 @@ self._write_size(0x50, len(value)) except UnicodeEncodeError: t = value.encode('utf-16be') - self._write_size(0x60, len(value)) + self._write_size(0x60, len(t) // 2) self._fp.write(t) diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -360,6 +360,13 @@ plistlib.dumps, testString) + def test_non_bmp_characters(self): + pl = {'python': '\U0001f40d'} + for fmt in ALL_FORMATS: + with self.subTest(fmt=fmt): + data = plistlib.dumps(pl, fmt=fmt) + self.assertEqual(plistlib.loads(data), pl) + def test_nondictroot(self): for fmt in ALL_FORMATS: with self.subTest(fmt=fmt): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ Library ------- +- Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. + - Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. - Issue #28227: gzip now supports pathlib. Patch by Ethan Furman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:39:30 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:39:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328229=3A_Merge_from_3=2E6?= Message-ID: <20161004173929.1569.73717.E80D06F7@psf.io> https://hg.python.org/cpython/rev/de398937653b changeset: 104288:de398937653b parent: 104286:b6c85e7e558a parent: 104287:b512780c6589 user: Berker Peksag date: Tue Oct 04 20:41:56 2016 +0300 summary: Issue #28229: Merge from 3.6 files: Doc/library/lzma.rst | 18 +++++++++++++----- Lib/lzma.py | 18 ++++++++++-------- Lib/test/test_lzma.py | 22 ++++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -39,8 +39,9 @@ object`. The *filename* argument can be either an actual file name (given as a - :class:`str` or :class:`bytes` object), in which case the named file is - opened, or it can be an existing file object to read from or write to. + :class:`str`, :class:`bytes` or :term:`path-like object` object), in + which case the named file is opened, or it can be an existing file object + to read from or write to. The *mode* argument can be any of ``"r"``, ``"rb"``, ``"w"``, ``"wb"``, ``"x"``, ``"xb"``, ``"a"`` or ``"ab"`` for binary mode, or ``"rt"``, @@ -64,6 +65,9 @@ .. versionchanged:: 3.4 Added support for the ``"x"``, ``"xb"`` and ``"xt"`` modes. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + .. class:: LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None) @@ -71,9 +75,10 @@ An :class:`LZMAFile` can wrap an already-open :term:`file object`, or operate directly on a named file. The *filename* argument specifies either the file - object to wrap, or the name of the file to open (as a :class:`str` or - :class:`bytes` object). When wrapping an existing file object, the wrapped - file will not be closed when the :class:`LZMAFile` is closed. + object to wrap, or the name of the file to open (as a :class:`str`, + :class:`bytes` or :term:`path-like object` object). When wrapping an + existing file object, the wrapped file will not be closed when the + :class:`LZMAFile` is closed. The *mode* argument can be either ``"r"`` for reading (default), ``"w"`` for overwriting, ``"x"`` for exclusive creation, or ``"a"`` for appending. These @@ -118,6 +123,9 @@ The :meth:`~io.BufferedIOBase.read` method now accepts an argument of ``None``. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + Compressing and decompressing data in memory -------------------------------------------- diff --git a/Lib/lzma.py b/Lib/lzma.py --- a/Lib/lzma.py +++ b/Lib/lzma.py @@ -23,6 +23,7 @@ import builtins import io +import os from _lzma import * from _lzma import _encode_filter_properties, _decode_filter_properties import _compression @@ -49,9 +50,10 @@ format=None, check=-1, preset=None, filters=None): """Open an LZMA-compressed file in binary mode. - filename can be either an actual file name (given as a str or - bytes object), in which case the named file is opened, or it can - be an existing file object to read from or write to. + filename can be either an actual file name (given as a str, + bytes, or PathLike object), in which case the named file is + opened, or it can be an existing file object to read from or + write to. mode can be "r" for reading (default), "w" for (over)writing, "x" for creating exclusively, or "a" for appending. These can @@ -112,7 +114,7 @@ else: raise ValueError("Invalid mode: {!r}".format(mode)) - if isinstance(filename, (str, bytes)): + if isinstance(filename, (str, bytes, os.PathLike)): if "b" not in mode: mode += "b" self._fp = builtins.open(filename, mode) @@ -122,7 +124,7 @@ self._fp = filename self._mode = mode_code else: - raise TypeError("filename must be a str or bytes object, or a file") + raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: raw = _compression.DecompressReader(self._fp, LZMADecompressor, @@ -263,9 +265,9 @@ encoding=None, errors=None, newline=None): """Open an LZMA-compressed file in binary or text mode. - filename can be either an actual file name (given as a str or bytes - object), in which case the named file is opened, or it can be an - existing file object to read from or write to. + filename can be either an actual file name (given as a str, bytes, + or PathLike object), in which case the named file is opened, or it + can be an existing file object to read from or write to. The mode argument can be "r", "rb" (default), "w", "wb", "x", "xb", "a", or "ab" for binary mode, or "rt", "wt", "xt", or "at" for text diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -1,6 +1,7 @@ import _compression from io import BytesIO, UnsupportedOperation, DEFAULT_BUFFER_SIZE import os +import pathlib import pickle import random import unittest @@ -488,6 +489,16 @@ with LZMAFile(BytesIO(), "a") as f: pass + def test_init_with_PathLike_filename(self): + filename = pathlib.Path(TESTFN) + with TempFile(filename, COMPRESSED_XZ): + with LZMAFile(filename) as f: + self.assertEqual(f.read(), INPUT) + with LZMAFile(filename, "a") as f: + f.write(INPUT) + with LZMAFile(filename) as f: + self.assertEqual(f.read(), INPUT * 2) + def test_init_with_filename(self): with TempFile(TESTFN, COMPRESSED_XZ): with LZMAFile(TESTFN) as f: @@ -1180,6 +1191,17 @@ with lzma.open(TESTFN, "rb") as f: self.assertEqual(f.read(), INPUT * 2) + def test_with_pathlike_filename(self): + filename = pathlib.Path(TESTFN) + with TempFile(filename): + with lzma.open(filename, "wb") as f: + f.write(INPUT) + with open(filename, "rb") as f: + file_data = lzma.decompress(f.read()) + self.assertEqual(file_data, INPUT) + with lzma.open(filename, "rb") as f: + self.assertEqual(f.read(), INPUT) + def test_bad_params(self): # Test invalid parameter combinations. with self.assertRaises(ValueError): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ Library ------- +- Issue #28229: lzma module now supports pathlib. + - Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. - Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:39:30 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:39:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjI5?= =?utf-8?q?=3A_lzma_module_now_supports_pathlib?= Message-ID: <20161004173929.82163.92190.A17FA59B@psf.io> https://hg.python.org/cpython/rev/b512780c6589 changeset: 104287:b512780c6589 branch: 3.6 parent: 104285:3a7234d04fe9 user: Berker Peksag date: Tue Oct 04 20:41:20 2016 +0300 summary: Issue #28229: lzma module now supports pathlib files: Doc/library/lzma.rst | 18 +++++++++++++----- Lib/lzma.py | 18 ++++++++++-------- Lib/test/test_lzma.py | 22 ++++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -39,8 +39,9 @@ object`. The *filename* argument can be either an actual file name (given as a - :class:`str` or :class:`bytes` object), in which case the named file is - opened, or it can be an existing file object to read from or write to. + :class:`str`, :class:`bytes` or :term:`path-like object` object), in + which case the named file is opened, or it can be an existing file object + to read from or write to. The *mode* argument can be any of ``"r"``, ``"rb"``, ``"w"``, ``"wb"``, ``"x"``, ``"xb"``, ``"a"`` or ``"ab"`` for binary mode, or ``"rt"``, @@ -64,6 +65,9 @@ .. versionchanged:: 3.4 Added support for the ``"x"``, ``"xb"`` and ``"xt"`` modes. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + .. class:: LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None) @@ -71,9 +75,10 @@ An :class:`LZMAFile` can wrap an already-open :term:`file object`, or operate directly on a named file. The *filename* argument specifies either the file - object to wrap, or the name of the file to open (as a :class:`str` or - :class:`bytes` object). When wrapping an existing file object, the wrapped - file will not be closed when the :class:`LZMAFile` is closed. + object to wrap, or the name of the file to open (as a :class:`str`, + :class:`bytes` or :term:`path-like object` object). When wrapping an + existing file object, the wrapped file will not be closed when the + :class:`LZMAFile` is closed. The *mode* argument can be either ``"r"`` for reading (default), ``"w"`` for overwriting, ``"x"`` for exclusive creation, or ``"a"`` for appending. These @@ -118,6 +123,9 @@ The :meth:`~io.BufferedIOBase.read` method now accepts an argument of ``None``. + .. versionchanged:: 3.6 + Accepts a :term:`path-like object`. + Compressing and decompressing data in memory -------------------------------------------- diff --git a/Lib/lzma.py b/Lib/lzma.py --- a/Lib/lzma.py +++ b/Lib/lzma.py @@ -23,6 +23,7 @@ import builtins import io +import os from _lzma import * from _lzma import _encode_filter_properties, _decode_filter_properties import _compression @@ -49,9 +50,10 @@ format=None, check=-1, preset=None, filters=None): """Open an LZMA-compressed file in binary mode. - filename can be either an actual file name (given as a str or - bytes object), in which case the named file is opened, or it can - be an existing file object to read from or write to. + filename can be either an actual file name (given as a str, + bytes, or PathLike object), in which case the named file is + opened, or it can be an existing file object to read from or + write to. mode can be "r" for reading (default), "w" for (over)writing, "x" for creating exclusively, or "a" for appending. These can @@ -112,7 +114,7 @@ else: raise ValueError("Invalid mode: {!r}".format(mode)) - if isinstance(filename, (str, bytes)): + if isinstance(filename, (str, bytes, os.PathLike)): if "b" not in mode: mode += "b" self._fp = builtins.open(filename, mode) @@ -122,7 +124,7 @@ self._fp = filename self._mode = mode_code else: - raise TypeError("filename must be a str or bytes object, or a file") + raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: raw = _compression.DecompressReader(self._fp, LZMADecompressor, @@ -263,9 +265,9 @@ encoding=None, errors=None, newline=None): """Open an LZMA-compressed file in binary or text mode. - filename can be either an actual file name (given as a str or bytes - object), in which case the named file is opened, or it can be an - existing file object to read from or write to. + filename can be either an actual file name (given as a str, bytes, + or PathLike object), in which case the named file is opened, or it + can be an existing file object to read from or write to. The mode argument can be "r", "rb" (default), "w", "wb", "x", "xb", "a", or "ab" for binary mode, or "rt", "wt", "xt", or "at" for text diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -1,6 +1,7 @@ import _compression from io import BytesIO, UnsupportedOperation, DEFAULT_BUFFER_SIZE import os +import pathlib import pickle import random import unittest @@ -488,6 +489,16 @@ with LZMAFile(BytesIO(), "a") as f: pass + def test_init_with_PathLike_filename(self): + filename = pathlib.Path(TESTFN) + with TempFile(filename, COMPRESSED_XZ): + with LZMAFile(filename) as f: + self.assertEqual(f.read(), INPUT) + with LZMAFile(filename, "a") as f: + f.write(INPUT) + with LZMAFile(filename) as f: + self.assertEqual(f.read(), INPUT * 2) + def test_init_with_filename(self): with TempFile(TESTFN, COMPRESSED_XZ): with LZMAFile(TESTFN) as f: @@ -1180,6 +1191,17 @@ with lzma.open(TESTFN, "rb") as f: self.assertEqual(f.read(), INPUT * 2) + def test_with_pathlike_filename(self): + filename = pathlib.Path(TESTFN) + with TempFile(filename): + with lzma.open(filename, "wb") as f: + f.write(INPUT) + with open(filename, "rb") as f: + file_data = lzma.decompress(f.read()) + self.assertEqual(file_data, INPUT) + with lzma.open(filename, "rb") as f: + self.assertEqual(f.read(), INPUT) + def test_bad_params(self): # Test invalid parameter combinations. with self.assertRaises(ValueError): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,8 @@ Library ------- +- Issue #28229: lzma module now supports pathlib. + - Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. - Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:44:17 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:44:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328348=3A_Merge_from_3=2E5?= Message-ID: <20161004174417.15775.11295.B4BB3FF2@psf.io> https://hg.python.org/cpython/rev/99c37fa72b66 changeset: 104290:99c37fa72b66 branch: 3.6 parent: 104287:b512780c6589 parent: 104289:8c8692da071a user: Berker Peksag date: Tue Oct 04 20:46:22 2016 +0300 summary: Issue #28348: Merge from 3.5 files: Doc/library/asyncio-task.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -374,7 +374,7 @@ A task is responsible for executing a coroutine object in an event loop. If the wrapped coroutine yields from a future, the task suspends the execution - of the wrapped coroutine and waits for the completition of the future. When + of the wrapped coroutine and waits for the completion of the future. When the future is done, the execution of the wrapped coroutine restarts with the result or the exception of the future. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:44:18 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:44:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328348=3A_Merge_from_3=2E6?= Message-ID: <20161004174417.95234.24434.D521F50F@psf.io> https://hg.python.org/cpython/rev/76591498aab7 changeset: 104291:76591498aab7 parent: 104288:de398937653b parent: 104290:99c37fa72b66 user: Berker Peksag date: Tue Oct 04 20:46:43 2016 +0300 summary: Issue #28348: Merge from 3.6 files: Doc/library/asyncio-task.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -374,7 +374,7 @@ A task is responsible for executing a coroutine object in an event loop. If the wrapped coroutine yields from a future, the task suspends the execution - of the wrapped coroutine and waits for the completition of the future. When + of the wrapped coroutine and waits for the completion of the future. When the future is done, the execution of the wrapped coroutine restarts with the result or the exception of the future. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:44:18 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:44:18 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzQ4?= =?utf-8?q?=3A_Fix_typo_in_asyncio=2ETask=28=29_documentation?= Message-ID: <20161004174417.85635.57770.13887973@psf.io> https://hg.python.org/cpython/rev/8c8692da071a changeset: 104289:8c8692da071a branch: 3.5 parent: 104284:381ef0f08f89 user: Berker Peksag date: Tue Oct 04 20:45:47 2016 +0300 summary: Issue #28348: Fix typo in asyncio.Task() documentation Patch by Mariatta Wijaya. files: Doc/library/asyncio-task.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -374,7 +374,7 @@ A task is responsible for executing a coroutine object in an event loop. If the wrapped coroutine yields from a future, the task suspends the execution - of the wrapped coroutine and waits for the completition of the future. When + of the wrapped coroutine and waits for the completion of the future. When the future is done, the execution of the wrapped coroutine restarts with the result or the exception of the future. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:53:28 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:53:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MjIy?= =?utf-8?q?=3A_Don=27t_fail_if_pygments_is_not_available?= Message-ID: <20161004175327.75862.70693.33F48EB0@psf.io> https://hg.python.org/cpython/rev/fa09ba71babb changeset: 104292:fa09ba71babb branch: 3.5 parent: 104289:8c8692da071a user: Berker Peksag date: Tue Oct 04 20:54:44 2016 +0300 summary: Issue #28222: Don't fail if pygments is not available We can't just skip the test if docutils is available, but pygments is not because the purpose of the test was testing a bug in _check_rst_data(). files: Lib/distutils/tests/test_check.py | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/distutils/tests/test_check.py b/Lib/distutils/tests/test_check.py --- a/Lib/distutils/tests/test_check.py +++ b/Lib/distutils/tests/test_check.py @@ -7,6 +7,12 @@ from distutils.tests import support from distutils.errors import DistutilsSetupError +try: + import pygments +except ImportError: + pygments = None + + class CheckTestCase(support.LoggingSilencer, support.TempdirManager, unittest.TestCase): @@ -119,9 +125,15 @@ pkg_info, dist = self.create_dist(long_description=rest_with_code) cmd = check(dist) cmd.check_restructuredtext() - self.assertEqual(cmd._warnings, 0) msgs = cmd._check_rst_data(rest_with_code) - self.assertEqual(len(msgs), 0) + if pygments is not None: + self.assertEqual(len(msgs), 0) + else: + self.assertEqual(len(msgs), 1) + self.assertEqual( + str(msgs[0][1]), + 'Cannot analyze code. Pygments package not found.' + ) def test_check_all(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:53:28 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:53:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328222=3A_Merge_from_3=2E6?= Message-ID: <20161004175327.82118.71813.977ED33C@psf.io> https://hg.python.org/cpython/rev/e0c1bc2e98ed changeset: 104294:e0c1bc2e98ed parent: 104291:76591498aab7 parent: 104293:d5eefcfa3458 user: Berker Peksag date: Tue Oct 04 20:55:52 2016 +0300 summary: Issue #28222: Merge from 3.6 files: Lib/distutils/tests/test_check.py | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/distutils/tests/test_check.py b/Lib/distutils/tests/test_check.py --- a/Lib/distutils/tests/test_check.py +++ b/Lib/distutils/tests/test_check.py @@ -7,6 +7,12 @@ from distutils.tests import support from distutils.errors import DistutilsSetupError +try: + import pygments +except ImportError: + pygments = None + + class CheckTestCase(support.LoggingSilencer, support.TempdirManager, unittest.TestCase): @@ -119,9 +125,15 @@ pkg_info, dist = self.create_dist(long_description=rest_with_code) cmd = check(dist) cmd.check_restructuredtext() - self.assertEqual(cmd._warnings, 0) msgs = cmd._check_rst_data(rest_with_code) - self.assertEqual(len(msgs), 0) + if pygments is not None: + self.assertEqual(len(msgs), 0) + else: + self.assertEqual(len(msgs), 1) + self.assertEqual( + str(msgs[0][1]), + 'Cannot analyze code. Pygments package not found.' + ) def test_check_all(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 13:53:50 2016 From: python-checkins at python.org (berker.peksag) Date: Tue, 04 Oct 2016 17:53:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328222=3A_Merge_from_3=2E5?= Message-ID: <20161004175327.1569.6367.F98E1F99@psf.io> https://hg.python.org/cpython/rev/d5eefcfa3458 changeset: 104293:d5eefcfa3458 branch: 3.6 parent: 104290:99c37fa72b66 parent: 104292:fa09ba71babb user: Berker Peksag date: Tue Oct 04 20:55:26 2016 +0300 summary: Issue #28222: Merge from 3.5 files: Lib/distutils/tests/test_check.py | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/distutils/tests/test_check.py b/Lib/distutils/tests/test_check.py --- a/Lib/distutils/tests/test_check.py +++ b/Lib/distutils/tests/test_check.py @@ -7,6 +7,12 @@ from distutils.tests import support from distutils.errors import DistutilsSetupError +try: + import pygments +except ImportError: + pygments = None + + class CheckTestCase(support.LoggingSilencer, support.TempdirManager, unittest.TestCase): @@ -119,9 +125,15 @@ pkg_info, dist = self.create_dist(long_description=rest_with_code) cmd = check(dist) cmd.check_restructuredtext() - self.assertEqual(cmd._warnings, 0) msgs = cmd._check_rst_data(rest_with_code) - self.assertEqual(len(msgs), 0) + if pygments is not None: + self.assertEqual(len(msgs), 0) + else: + self.assertEqual(len(msgs), 1) + self.assertEqual( + str(msgs[0][1]), + 'Cannot analyze code. Pygments package not found.' + ) def test_check_all(self): -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Tue Oct 4 14:14:05 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 4 Oct 2016 19:14:05 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-04 Message-ID: No new revisions. Here are the previous results: Results for project Python 2.7, build date 2016-10-04 08:44:18 +0000 commit: a0b9c4f98573 previous commit: f256bd5b8418 revision date: 2016-10-02 18:16:28 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% 0.06% 3.76% 7.66% :-) pybench 0.19% -0.16% 6.05% 3.65% :-( regex_v8 0.65% -0.01% -2.22% 10.55% :-) nbody 0.19% -0.16% 7.28% 4.83% :-| json_dump_v2 0.33% 0.27% 1.88% 10.49% :-| normal_startup 0.59% 0.32% -0.53% 2.75% :-) ssbench 0.17% 0.06% 2.14% 1.74% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-04/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Tue Oct 4 14:15:27 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 4 Oct 2016 19:15:27 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-04 Message-ID: <37c4eb3c-4056-4b5e-9cff-2f7c387bd1b8@irsmsx101.ger.corp.intel.com> Results for project Python default, build date 2016-10-04 07:57:49 +0000 commit: 3fed30fa37f4 previous commit: 36b052adf5a7 revision date: 2016-10-04 07:01:03 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.25% -0.23% 4.78% 16.40% :-) pybench 0.10% 0.38% 5.74% 3.88% :-( regex_v8 3.71% 0.93% -3.72% 3.99% :-) nbody 0.10% 2.40% 5.04% 2.48% :-( json_dump_v2 0.28% -1.07% -14.57% 18.71% :-) normal_startup 0.24% -0.32% 3.95% 6.40% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-04/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Tue Oct 4 14:52:23 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 04 Oct 2016 18:52:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_null_merge_from_3=2E6?= Message-ID: <20161004185223.85616.58917.0A238C68@psf.io> https://hg.python.org/cpython/rev/71fd5d2447d4 changeset: 104296:71fd5d2447d4 parent: 104294:e0c1bc2e98ed parent: 104295:de0fa478c22e user: Ned Deily date: Tue Oct 04 14:52:01 2016 -0400 summary: null merge from 3.6 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 4 14:52:23 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 04 Oct 2016 18:52:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI3MTgx?= =?utf-8?q?_remove_geometric=5Fmean_and_defer_for_3=2E7=2E?= Message-ID: <20161004185223.76110.40867.B65FCEF4@psf.io> https://hg.python.org/cpython/rev/de0fa478c22e changeset: 104295:de0fa478c22e branch: 3.6 parent: 104293:d5eefcfa3458 user: Steven D'Aprano date: Wed Oct 05 03:24:45 2016 +1100 summary: Issue #27181 remove geometric_mean and defer for 3.7. files: Doc/library/statistics.rst | 29 -- Lib/statistics.py | 269 +----------------------- Lib/test/test_statistics.py | 267 ----------------------- Misc/NEWS | 2 + 4 files changed, 3 insertions(+), 564 deletions(-) diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -39,7 +39,6 @@ ======================= ============================================= :func:`mean` Arithmetic mean ("average") of data. -:func:`geometric_mean` Geometric mean of data. :func:`harmonic_mean` Harmonic mean of data. :func:`median` Median (middle value) of data. :func:`median_low` Low median of data. @@ -113,34 +112,6 @@ ``mean(data)`` is equivalent to calculating the true population mean ?. -.. function:: geometric_mean(data) - - Return the geometric mean of *data*, a sequence or iterator of - real-valued numbers. - - The geometric mean is the *n*-th root of the product of *n* data points. - It is a type of average, a measure of the central location of the data. - - The geometric mean is appropriate when averaging quantities which - are multiplied together rather than added, for example growth rates. - Suppose an investment grows by 10% in the first year, falls by 5% in - the second, then grows by 12% in the third, what is the average rate - of growth over the three years? - - .. doctest:: - - >>> geometric_mean([1.10, 0.95, 1.12]) - 1.0538483123382172 - - giving an average growth of 5.385%. Using the arithmetic mean will - give approximately 5.667%, which is too high. - - :exc:`StatisticsError` is raised if *data* is empty, or any - element is less than zero. - - .. versionadded:: 3.6 - - .. function:: harmonic_mean(data) Return the harmonic mean of *data*, a sequence or iterator of diff --git a/Lib/statistics.py b/Lib/statistics.py --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -11,7 +11,6 @@ Function Description ================== ============================================= mean Arithmetic mean (average) of data. -geometric_mean Geometric mean of data. harmonic_mean Harmonic mean of data. median Median (middle value) of data. median_low Low median of data. @@ -80,7 +79,7 @@ __all__ = [ 'StatisticsError', 'pstdev', 'pvariance', 'stdev', 'variance', 'median', 'median_low', 'median_high', 'median_grouped', - 'mean', 'mode', 'geometric_mean', 'harmonic_mean', + 'mean', 'mode', 'harmonic_mean', ] import collections @@ -287,229 +286,6 @@ yield x -class _nroot_NS: - """Hands off! Don't touch! - - Everything inside this namespace (class) is an even-more-private - implementation detail of the private _nth_root function. - """ - # This class exists only to be used as a namespace, for convenience - # of being able to keep the related functions together, and to - # collapse the group in an editor. If this were C# or C++, I would - # use a Namespace, but the closest Python has is a class. - # - # FIXME possibly move this out into a separate module? - # That feels like overkill, and may encourage people to treat it as - # a public feature. - def __init__(self): - raise TypeError('namespace only, do not instantiate') - - def nth_root(x, n): - """Return the positive nth root of numeric x. - - This may be more accurate than ** or pow(): - - >>> math.pow(1000, 1.0/3) #doctest:+SKIP - 9.999999999999998 - - >>> _nth_root(1000, 3) - 10.0 - >>> _nth_root(11**5, 5) - 11.0 - >>> _nth_root(2, 12) - 1.0594630943592953 - - """ - if not isinstance(n, int): - raise TypeError('degree n must be an int') - if n < 2: - raise ValueError('degree n must be 2 or more') - if isinstance(x, decimal.Decimal): - return _nroot_NS.decimal_nroot(x, n) - elif isinstance(x, numbers.Real): - return _nroot_NS.float_nroot(x, n) - else: - raise TypeError('expected a number, got %s') % type(x).__name__ - - def float_nroot(x, n): - """Handle nth root of Reals, treated as a float.""" - assert isinstance(n, int) and n > 1 - if x < 0: - raise ValueError('domain error: root of negative number') - elif x == 0: - return math.copysign(0.0, x) - elif x > 0: - try: - isinfinity = math.isinf(x) - except OverflowError: - return _nroot_NS.bignum_nroot(x, n) - else: - if isinfinity: - return float('inf') - else: - return _nroot_NS.nroot(x, n) - else: - assert math.isnan(x) - return float('nan') - - def nroot(x, n): - """Calculate x**(1/n), then improve the answer.""" - # This uses math.pow() to calculate an initial guess for the root, - # then uses the iterated nroot algorithm to improve it. - # - # By my testing, about 8% of the time the iterated algorithm ends - # up converging to a result which is less accurate than the initial - # guess. [FIXME: is this still true?] In that case, we use the - # guess instead of the "improved" value. This way, we're never - # less accurate than math.pow(). - r1 = math.pow(x, 1.0/n) - eps1 = abs(r1**n - x) - if eps1 == 0.0: - # r1 is the exact root, so we're done. By my testing, this - # occurs about 80% of the time for x < 1 and 30% of the - # time for x > 1. - return r1 - else: - try: - r2 = _nroot_NS.iterated_nroot(x, n, r1) - except RuntimeError: - return r1 - else: - eps2 = abs(r2**n - x) - if eps1 < eps2: - return r1 - return r2 - - def iterated_nroot(a, n, g): - """Return the nth root of a, starting with guess g. - - This is a special case of Newton's Method. - https://en.wikipedia.org/wiki/Nth_root_algorithm - """ - np = n - 1 - def iterate(r): - try: - return (np*r + a/math.pow(r, np))/n - except OverflowError: - # If r is large enough, r**np may overflow. If that - # happens, r**-np will be small, but not necessarily zero. - return (np*r + a*math.pow(r, -np))/n - # With a good guess, such as g = a**(1/n), this will converge in - # only a few iterations. However a poor guess can take thousands - # of iterations to converge, if at all. We guard against poor - # guesses by setting an upper limit to the number of iterations. - r1 = g - r2 = iterate(g) - for i in range(1000): - if r1 == r2: - break - # Use Floyd's cycle-finding algorithm to avoid being trapped - # in a cycle. - # https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare - r1 = iterate(r1) - r2 = iterate(iterate(r2)) - else: - # If the guess is particularly bad, the above may fail to - # converge in any reasonable time. - raise RuntimeError('nth-root failed to converge') - return r2 - - def decimal_nroot(x, n): - """Handle nth root of Decimals.""" - assert isinstance(x, decimal.Decimal) - assert isinstance(n, int) - if x.is_snan(): - # Signalling NANs always raise. - raise decimal.InvalidOperation('nth-root of snan') - if x.is_qnan(): - # Quiet NANs only raise if the context is set to raise, - # otherwise return a NAN. - ctx = decimal.getcontext() - if ctx.traps[decimal.InvalidOperation]: - raise decimal.InvalidOperation('nth-root of nan') - else: - # Preserve the input NAN. - return x - if x < 0: - raise ValueError('domain error: root of negative number') - if x.is_infinite(): - return x - # FIXME this hasn't had the extensive testing of the float - # version _iterated_nroot so there's possibly some buggy - # corner cases buried in here. Can it overflow? Fail to - # converge or get trapped in a cycle? Converge to a less - # accurate root? - np = n - 1 - def iterate(r): - return (np*r + x/r**np)/n - r0 = x**(decimal.Decimal(1)/n) - assert isinstance(r0, decimal.Decimal) - r1 = iterate(r0) - while True: - if r1 == r0: - return r1 - r0, r1 = r1, iterate(r1) - - def bignum_nroot(x, n): - """Return the nth root of a positive huge number.""" - assert x > 0 - # I state without proof that ??x ? ??2???(x//2) - # and that for sufficiently big x the error is acceptable. - # We now halve x until it is small enough to get the root. - m = 0 - while True: - x //= 2 - m += 1 - try: - y = float(x) - except OverflowError: - continue - break - a = _nroot_NS.nroot(y, n) - # At this point, we want the nth-root of 2**m, or 2**(m/n). - # We can write that as 2**(q + r/n) = 2**q * ??2**r where q = m//n. - q, r = divmod(m, n) - b = 2**q * _nroot_NS.nroot(2**r, n) - return a * b - - -# This is the (private) function for calculating nth roots: -_nth_root = _nroot_NS.nth_root -assert type(_nth_root) is type(lambda: None) - - -def _product(values): - """Return product of values as (exponent, mantissa).""" - errmsg = 'mixed Decimal and float is not supported' - prod = 1 - for x in values: - if isinstance(x, float): - break - prod *= x - else: - return (0, prod) - if isinstance(prod, Decimal): - raise TypeError(errmsg) - # Since floats can overflow easily, we calculate the product as a - # sort of poor-man's BigFloat. Given that: - # - # x = 2**p * m # p == power or exponent (scale), m = mantissa - # - # we can calculate the product of two (or more) x values as: - # - # x1*x2 = 2**p1*m1 * 2**p2*m2 = 2**(p1+p2)*(m1*m2) - # - mant, scale = 1, 0 #math.frexp(prod) # FIXME - for y in chain([x], values): - if isinstance(y, Decimal): - raise TypeError(errmsg) - m1, e1 = math.frexp(y) - m2, e2 = math.frexp(mant) - scale += (e1 + e2) - mant = m1*m2 - return (scale, mant) - - # === Measures of central tendency (averages) === def mean(data): @@ -538,49 +314,6 @@ return _convert(total/n, T) -def geometric_mean(data): - """Return the geometric mean of data. - - The geometric mean is appropriate when averaging quantities which - are multiplied together rather than added, for example growth rates. - Suppose an investment grows by 10% in the first year, falls by 5% in - the second, then grows by 12% in the third, what is the average rate - of growth over the three years? - - >>> geometric_mean([1.10, 0.95, 1.12]) - 1.0538483123382172 - - giving an average growth of 5.385%. Using the arithmetic mean will - give approximately 5.667%, which is too high. - - ``StatisticsError`` will be raised if ``data`` is empty, or any - element is less than zero. - """ - if iter(data) is data: - data = list(data) - errmsg = 'geometric mean does not support negative values' - n = len(data) - if n < 1: - raise StatisticsError('geometric_mean requires at least one data point') - elif n == 1: - x = data[0] - if isinstance(g, (numbers.Real, Decimal)): - if x < 0: - raise StatisticsError(errmsg) - return x - else: - raise TypeError('unsupported type') - else: - scale, prod = _product(_fail_neg(data, errmsg)) - r = _nth_root(prod, n) - if scale: - p, q = divmod(scale, n) - s = 2**p * _nth_root(2**q, n) - else: - s = 1 - return s*r - - def harmonic_mean(data): """Return the harmonic mean of data. diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1010,273 +1010,6 @@ self.assertEqual(errmsg, msg) -class Test_Product(NumericTestCase): - """Test the private _product function.""" - - def test_ints(self): - data = [1, 2, 5, 7, 9] - self.assertEqual(statistics._product(data), (0, 630)) - self.assertEqual(statistics._product(data*100), (0, 630**100)) - - def test_floats(self): - data = [1.0, 2.0, 4.0, 8.0] - self.assertEqual(statistics._product(data), (8, 0.25)) - - def test_overflow(self): - # Test with floats that overflow. - data = [1e300]*5 - self.assertEqual(statistics._product(data), (5980, 0.6928287951283193)) - - def test_fractions(self): - F = Fraction - data = [F(14, 23), F(69, 1), F(665, 529), F(299, 105), F(1683, 39)] - exp, mant = statistics._product(data) - self.assertEqual(exp, 0) - self.assertEqual(mant, F(2*3*7*11*17*19, 23)) - self.assertTrue(isinstance(mant, F)) - # Mixed Fraction and int. - data = [3, 25, F(2, 15)] - exp, mant = statistics._product(data) - self.assertEqual(exp, 0) - self.assertEqual(mant, F(10)) - self.assertTrue(isinstance(mant, F)) - - def test_decimal(self): - D = Decimal - data = [D('24.5'), D('17.6'), D('0.025'), D('1.3')] - expected = D('14.014000') - self.assertEqual(statistics._product(data), (0, expected)) - - def test_mixed_decimal_float(self): - # Test that mixed Decimal and float raises. - self.assertRaises(TypeError, statistics._product, [1.0, Decimal(1)]) - self.assertRaises(TypeError, statistics._product, [Decimal(1), 1.0]) - - - at unittest.skipIf(True, "FIXME: tests known to fail, see issue #27181") -class Test_Nth_Root(NumericTestCase): - """Test the functionality of the private _nth_root function.""" - - def setUp(self): - self.nroot = statistics._nth_root - - # --- Special values (infinities, NANs, zeroes) --- - - def test_float_NAN(self): - # Test that the root of a float NAN is a float NAN. - NAN = float('nan') - for n in range(2, 9): - with self.subTest(n=n): - result = self.nroot(NAN, n) - self.assertTrue(math.isnan(result)) - - def test_decimal_QNAN(self): - # Test the behaviour when taking the root of a Decimal quiet NAN. - NAN = decimal.Decimal('nan') - with decimal.localcontext() as ctx: - ctx.traps[decimal.InvalidOperation] = 1 - self.assertRaises(decimal.InvalidOperation, self.nroot, NAN, 5) - ctx.traps[decimal.InvalidOperation] = 0 - self.assertTrue(self.nroot(NAN, 5).is_qnan()) - - def test_decimal_SNAN(self): - # Test that taking the root of a Decimal sNAN always raises. - sNAN = decimal.Decimal('snan') - with decimal.localcontext() as ctx: - ctx.traps[decimal.InvalidOperation] = 1 - self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) - ctx.traps[decimal.InvalidOperation] = 0 - self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) - - def test_inf(self): - # Test that the root of infinity is infinity. - for INF in (float('inf'), decimal.Decimal('inf')): - for n in range(2, 9): - with self.subTest(n=n, inf=INF): - self.assertEqual(self.nroot(INF, n), INF) - - # FIXME: need to check Decimal zeroes too. - def test_zero(self): - # Test that the root of +0.0 is +0.0. - for n in range(2, 11): - with self.subTest(n=n): - result = self.nroot(+0.0, n) - self.assertEqual(result, 0.0) - self.assertEqual(sign(result), +1) - - # FIXME: need to check Decimal zeroes too. - def test_neg_zero(self): - # Test that the root of -0.0 is -0.0. - for n in range(2, 11): - with self.subTest(n=n): - result = self.nroot(-0.0, n) - self.assertEqual(result, 0.0) - self.assertEqual(sign(result), -1) - - # --- Test return types --- - - def check_result_type(self, x, n, outtype): - self.assertIsInstance(self.nroot(x, n), outtype) - class MySubclass(type(x)): - pass - self.assertIsInstance(self.nroot(MySubclass(x), n), outtype) - - def testDecimal(self): - # Test that Decimal arguments return Decimal results. - self.check_result_type(decimal.Decimal('33.3'), 3, decimal.Decimal) - - def testFloat(self): - # Test that other arguments return float results. - for x in (0.2, Fraction(11, 7), 91): - self.check_result_type(x, 6, float) - - # --- Test bad input --- - - def testBadOrderTypes(self): - # Test that nroot raises correctly when n has the wrong type. - for n in (5.0, 2j, None, 'x', b'x', [], {}, set(), sign): - with self.subTest(n=n): - self.assertRaises(TypeError, self.nroot, 2.5, n) - - def testBadOrderValues(self): - # Test that nroot raises correctly when n has a wrong value. - for n in (1, 0, -1, -2, -87): - with self.subTest(n=n): - self.assertRaises(ValueError, self.nroot, 2.5, n) - - def testBadTypes(self): - # Test that nroot raises correctly when x has the wrong type. - for x in (None, 'x', b'x', [], {}, set(), sign): - with self.subTest(x=x): - self.assertRaises(TypeError, self.nroot, x, 3) - - def testNegativeError(self): - # Test negative x raises correctly. - x = random.uniform(-20.0, -0.1) - assert x < 0 - for n in range(3, 7): - with self.subTest(x=x, n=n): - self.assertRaises(ValueError, self.nroot, x, n) - # And Decimal. - self.assertRaises(ValueError, self.nroot, Decimal(-27), 3) - - # --- Test that nroot is never worse than calling math.pow() --- - - def check_error_is_no_worse(self, x, n): - y = math.pow(x, n) - with self.subTest(x=x, n=n, y=y): - err1 = abs(self.nroot(y, n) - x) - err2 = abs(math.pow(y, 1.0/n) - x) - self.assertLessEqual(err1, err2) - - def testCompareWithPowSmall(self): - # Compare nroot with pow for small values of x. - for i in range(200): - x = random.uniform(1e-9, 1.0-1e-9) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowMedium(self): - # Compare nroot with pow for medium-sized values of x. - for i in range(200): - x = random.uniform(1.0, 100.0) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowLarge(self): - # Compare nroot with pow for largish values of x. - for i in range(200): - x = random.uniform(100.0, 10000.0) - n = random.choice(range(2, 16)) - self.check_error_is_no_worse(x, n) - - def testCompareWithPowHuge(self): - # Compare nroot with pow for huge values of x. - for i in range(200): - x = random.uniform(1e20, 1e50) - # We restrict the order here to avoid an Overflow error. - n = random.choice(range(2, 7)) - self.check_error_is_no_worse(x, n) - - # --- Test for numerically correct answers --- - - def testExactPowers(self): - # Test that small integer powers are calculated exactly. - for i in range(1, 51): - for n in range(2, 16): - if (i, n) == (35, 13): - # See testExpectedFailure35p13 - continue - with self.subTest(i=i, n=n): - x = i**n - self.assertEqual(self.nroot(x, n), i) - - def testExpectedFailure35p13(self): - # Test the expected failure 35**13 is almost exact. - x = 35**13 - err = abs(self.nroot(x, 13) - 35) - self.assertLessEqual(err, 0.000000001) - - def testOne(self): - # Test that the root of 1.0 is 1.0. - for n in range(2, 11): - with self.subTest(n=n): - self.assertEqual(self.nroot(1.0, n), 1.0) - - def testFraction(self): - # Test Fraction results. - x = Fraction(89, 75) - self.assertEqual(self.nroot(x**12, 12), float(x)) - - def testInt(self): - # Test int results. - x = 276 - self.assertEqual(self.nroot(x**24, 24), x) - - def testBigInt(self): - # Test that ints too big to convert to floats work. - bignum = 10**20 # That's not that big... - self.assertEqual(self.nroot(bignum**280, 280), bignum) - # Can we make it bigger? - hugenum = bignum**50 - # Make sure that it is too big to convert to a float. - try: - y = float(hugenum) - except OverflowError: - pass - else: - raise AssertionError('hugenum is not big enough') - self.assertEqual(self.nroot(hugenum, 50), float(bignum)) - - def testDecimal(self): - # Test Decimal results. - for s in '3.759 64.027 5234.338'.split(): - x = decimal.Decimal(s) - with self.subTest(x=x): - a = self.nroot(x**5, 5) - self.assertEqual(a, x) - a = self.nroot(x**17, 17) - self.assertEqual(a, x) - - def testFloat(self): - # Test float results. - for x in (3.04e-16, 18.25, 461.3, 1.9e17): - with self.subTest(x=x): - self.assertEqual(self.nroot(x**3, 3), x) - self.assertEqual(self.nroot(x**8, 8), x) - self.assertEqual(self.nroot(x**11, 11), x) - - -class Test_NthRoot_NS(unittest.TestCase): - """Test internals of the nth_root function, hidden in _nroot_NS.""" - - def test_class_cannot_be_instantiated(self): - # Test that _nroot_NS cannot be instantiated. - # It should be a namespace, like in C++ or C#, but Python - # lacks that feature and so we have to make do with a class. - self.assertRaises(TypeError, statistics._nroot_NS) - - # === Tests for public functions === class UnivariateCommonMixin: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,8 @@ Library ------- +- Issue #27181 remove statistics.geometric_mean and defer until 3.7. + - Issue #28229: lzma module now supports pathlib. - Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Wed Oct 5 10:45:34 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 5 Oct 2016 15:45:34 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-05 Message-ID: <16514c07-c10d-486e-af0d-bb6819c4326d@irsmsx103.ger.corp.intel.com> Results for project Python default, build date 2016-10-05 02:01:01 +0000 commit: 71fd5d2447d4 previous commit: 3fed30fa37f4 revision date: 2016-10-04 18:52:01 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% 0.37% 5.13% 15.25% :-) pybench 0.13% -0.18% 5.57% 4.34% :-( regex_v8 3.72% -0.02% -3.74% 1.39% :-) nbody 0.10% -1.39% 3.72% 2.38% :-( json_dump_v2 0.25% 1.74% -12.57% 15.95% :-) normal_startup 0.56% 0.10% 4.27% 6.30% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-05/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Wed Oct 5 10:45:13 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 5 Oct 2016 15:45:13 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python 2.7 2016-10-05 Message-ID: Results for project Python 2.7, build date 2016-10-05 02:47:16 +0000 commit: 522adc2e082a previous commit: a0b9c4f98573 revision date: 2016-10-04 15:17:08 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% 1.61% 5.31% 3.23% :-) pybench 0.22% -0.08% 5.97% 4.19% :-( regex_v8 0.66% -0.03% -2.25% 11.13% :-) nbody 0.05% 0.21% 7.47% 6.85% :-) json_dump_v2 0.30% 1.10% 2.96% 9.77% :-| normal_startup 0.62% 0.03% -0.50% 2.61% :-| ssbench 0.19% -0.14% 2.00% 2.01% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-2-7-2016-10-05/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Wed Oct 5 16:18:56 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 05 Oct 2016 20:18:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327998=3A_Removed_workarounds_for_supporting_byt?= =?utf-8?q?es_paths_on_Windows_in?= Message-ID: <20161005201856.94922.27422.D892EFE9@psf.io> https://hg.python.org/cpython/rev/bcee710c42fe changeset: 104298:bcee710c42fe parent: 104296:71fd5d2447d4 parent: 104297:7c36e6fd0232 user: Serhiy Storchaka date: Wed Oct 05 23:18:32 2016 +0300 summary: Issue #27998: Removed workarounds for supporting bytes paths on Windows in os.walk() function and glob module since os.scandir() now directly supports them. files: Lib/glob.py | 23 ++++--------- Lib/os.py | 70 +--------------------------------------- 2 files changed, 10 insertions(+), 83 deletions(-) diff --git a/Lib/glob.py b/Lib/glob.py --- a/Lib/glob.py +++ b/Lib/glob.py @@ -118,22 +118,13 @@ else: dirname = os.curdir try: - if os.name == 'nt' and isinstance(dirname, bytes): - names = os.listdir(dirname) - if dironly: - for name in names: - if os.path.isdir(os.path.join(dirname, name)): - yield name - else: - yield from names - else: - with os.scandir(dirname) as it: - for entry in it: - try: - if not dironly or entry.is_dir(): - yield entry.name - except OSError: - pass + with os.scandir(dirname) as it: + for entry in it: + try: + if not dironly or entry.is_dir(): + yield entry.name + except OSError: + pass except OSError: return diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -343,12 +343,9 @@ # minor reason when (say) a thousand readable directories are still # left to visit. That logic is copied here. try: - if name == 'nt' and isinstance(top, bytes): - scandir_it = _dummy_scandir(top) - else: - # Note that scandir is global in this module due - # to earlier import-*. - scandir_it = scandir(top) + # Note that scandir is global in this module due + # to earlier import-*. + scandir_it = scandir(top) except OSError as error: if onerror is not None: onerror(error) @@ -417,67 +414,6 @@ # Yield after recursion if going bottom up yield top, dirs, nondirs -class _DummyDirEntry: - """Dummy implementation of DirEntry - - Only used internally by os.walk(bytes). Since os.walk() doesn't need the - follow_symlinks parameter: don't implement it, always follow symbolic - links. - """ - - def __init__(self, dir, name): - self.name = name - self.path = path.join(dir, name) - # Mimick FindFirstFile/FindNextFile: we should get file attributes - # while iterating on a directory - self._stat = None - self._lstat = None - try: - self.stat(follow_symlinks=False) - except OSError: - pass - - def stat(self, *, follow_symlinks=True): - if follow_symlinks: - if self._stat is None: - self._stat = stat(self.path) - return self._stat - else: - if self._lstat is None: - self._lstat = stat(self.path, follow_symlinks=False) - return self._lstat - - def is_dir(self): - if self._lstat is not None and not self.is_symlink(): - # use the cache lstat - stat = self.stat(follow_symlinks=False) - return st.S_ISDIR(stat.st_mode) - - stat = self.stat() - return st.S_ISDIR(stat.st_mode) - - def is_symlink(self): - stat = self.stat(follow_symlinks=False) - return st.S_ISLNK(stat.st_mode) - -class _dummy_scandir: - # listdir-based implementation for bytes patches on Windows - def __init__(self, dir): - self.dir = dir - self.it = iter(listdir(dir)) - - def __iter__(self): - return self - - def __next__(self): - return _DummyDirEntry(self.dir, next(self.it)) - - def __enter__(self): - return self - - def __exit__(self, *args): - self.it = iter(()) - __all__.append("walk") if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 16:18:56 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 05 Oct 2016 20:18:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI3OTk4?= =?utf-8?q?=3A_Removed_workarounds_for_supporting_bytes_paths_on_Windows_i?= =?utf-8?q?n?= Message-ID: <20161005201855.82206.37101.0F5E6D4D@psf.io> https://hg.python.org/cpython/rev/7c36e6fd0232 changeset: 104297:7c36e6fd0232 branch: 3.6 parent: 104295:de0fa478c22e user: Serhiy Storchaka date: Wed Oct 05 23:17:10 2016 +0300 summary: Issue #27998: Removed workarounds for supporting bytes paths on Windows in os.walk() function and glob module since os.scandir() now directly supports them. files: Lib/glob.py | 23 ++++--------- Lib/os.py | 70 +--------------------------------------- 2 files changed, 10 insertions(+), 83 deletions(-) diff --git a/Lib/glob.py b/Lib/glob.py --- a/Lib/glob.py +++ b/Lib/glob.py @@ -118,22 +118,13 @@ else: dirname = os.curdir try: - if os.name == 'nt' and isinstance(dirname, bytes): - names = os.listdir(dirname) - if dironly: - for name in names: - if os.path.isdir(os.path.join(dirname, name)): - yield name - else: - yield from names - else: - with os.scandir(dirname) as it: - for entry in it: - try: - if not dironly or entry.is_dir(): - yield entry.name - except OSError: - pass + with os.scandir(dirname) as it: + for entry in it: + try: + if not dironly or entry.is_dir(): + yield entry.name + except OSError: + pass except OSError: return diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -343,12 +343,9 @@ # minor reason when (say) a thousand readable directories are still # left to visit. That logic is copied here. try: - if name == 'nt' and isinstance(top, bytes): - scandir_it = _dummy_scandir(top) - else: - # Note that scandir is global in this module due - # to earlier import-*. - scandir_it = scandir(top) + # Note that scandir is global in this module due + # to earlier import-*. + scandir_it = scandir(top) except OSError as error: if onerror is not None: onerror(error) @@ -417,67 +414,6 @@ # Yield after recursion if going bottom up yield top, dirs, nondirs -class _DummyDirEntry: - """Dummy implementation of DirEntry - - Only used internally by os.walk(bytes). Since os.walk() doesn't need the - follow_symlinks parameter: don't implement it, always follow symbolic - links. - """ - - def __init__(self, dir, name): - self.name = name - self.path = path.join(dir, name) - # Mimick FindFirstFile/FindNextFile: we should get file attributes - # while iterating on a directory - self._stat = None - self._lstat = None - try: - self.stat(follow_symlinks=False) - except OSError: - pass - - def stat(self, *, follow_symlinks=True): - if follow_symlinks: - if self._stat is None: - self._stat = stat(self.path) - return self._stat - else: - if self._lstat is None: - self._lstat = stat(self.path, follow_symlinks=False) - return self._lstat - - def is_dir(self): - if self._lstat is not None and not self.is_symlink(): - # use the cache lstat - stat = self.stat(follow_symlinks=False) - return st.S_ISDIR(stat.st_mode) - - stat = self.stat() - return st.S_ISDIR(stat.st_mode) - - def is_symlink(self): - stat = self.stat(follow_symlinks=False) - return st.S_ISLNK(stat.st_mode) - -class _dummy_scandir: - # listdir-based implementation for bytes patches on Windows - def __init__(self, dir): - self.dir = dir - self.it = iter(listdir(dir)) - - def __iter__(self): - return self - - def __next__(self): - return _DummyDirEntry(self.dir, next(self.it)) - - def __enter__(self): - return self - - def __exit__(self, *args): - self.it = iter(()) - __all__.append("walk") if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 17:02:30 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 21:02:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzY4?= =?utf-8?q?=3A_Refuse_monitoring_processes_if_the_child_watcher_has_no_loo?= =?utf-8?q?p?= Message-ID: <20161005210212.1419.56008.1F63FA61@psf.io> https://hg.python.org/cpython/rev/2110dcef5892 changeset: 104299:2110dcef5892 branch: 3.5 parent: 104292:fa09ba71babb user: Yury Selivanov date: Wed Oct 05 16:57:12 2016 -0400 summary: Issue #28368: Refuse monitoring processes if the child watcher has no loop attached. Patch by Vincent Michel. files: Lib/asyncio/unix_events.py | 23 ++++++++-- Lib/test/test_asyncio/test_subprocess.py | 7 +++ Lib/test/test_asyncio/test_unix_events.py | 14 ++++++- Misc/NEWS | 4 + 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -746,6 +746,7 @@ def __init__(self): self._loop = None + self._callbacks = {} def close(self): self.attach_loop(None) @@ -759,6 +760,12 @@ def attach_loop(self, loop): assert loop is None or isinstance(loop, events.AbstractEventLoop) + if self._loop is not None and loop is None and self._callbacks: + warnings.warn( + 'A loop is being detached ' + 'from a child watcher with pending handlers', + RuntimeWarning) + if self._loop is not None: self._loop.remove_signal_handler(signal.SIGCHLD) @@ -807,10 +814,6 @@ big number of children (O(n) each time SIGCHLD is raised) """ - def __init__(self): - super().__init__() - self._callbacks = {} - def close(self): self._callbacks.clear() super().close() @@ -822,6 +825,11 @@ pass def add_child_handler(self, pid, callback, *args): + if self._loop is None: + raise RuntimeError( + "Cannot add child handler, " + "the child watcher does not have a loop attached") + self._callbacks[pid] = (callback, args) # Prevent a race condition in case the child is already terminated. @@ -886,7 +894,6 @@ """ def __init__(self): super().__init__() - self._callbacks = {} self._lock = threading.Lock() self._zombies = {} self._forks = 0 @@ -918,6 +925,12 @@ def add_child_handler(self, pid, callback, *args): assert self._forks, "Must use the context manager" + + if self._loop is None: + raise RuntimeError( + "Cannot add child handler, " + "the child watcher does not have a loop attached") + with self._lock: try: returncode = self._zombies.pop(pid) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -433,6 +433,13 @@ # the transport was not notified yet self.assertFalse(killed) + # Unlike SafeChildWatcher, FastChildWatcher does not pop the + # callbacks if waitpid() is called elsewhere. Let's clear them + # manually to avoid a warning when the watcher is detached. + if sys.platform != 'win32' and \ + isinstance(self, SubprocessFastWatcherTests): + asyncio.get_child_watcher()._callbacks.clear() + def test_popen_error(self): # Issue #24763: check that the subprocess transport is closed # when BaseSubprocessTransport fails diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -11,6 +11,7 @@ import tempfile import threading import unittest +import warnings from unittest import mock if sys.platform == 'win32': @@ -1391,7 +1392,9 @@ with mock.patch.object( old_loop, "remove_signal_handler") as m_remove_signal_handler: - self.watcher.attach_loop(None) + with self.assertWarnsRegex( + RuntimeWarning, 'A loop is being detached'): + self.watcher.attach_loop(None) m_remove_signal_handler.assert_called_once_with( signal.SIGCHLD) @@ -1463,6 +1466,15 @@ if isinstance(self.watcher, asyncio.FastChildWatcher): self.assertFalse(self.watcher._zombies) + @waitpid_mocks + def test_add_child_handler_with_no_loop_attached(self, m): + callback = mock.Mock() + with self.create_watcher() as watcher: + with self.assertRaisesRegex( + RuntimeError, + 'the child watcher does not have a loop attached'): + watcher.add_child_handler(100, callback) + class SafeChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase): def create_watcher(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -346,6 +346,10 @@ - Issue #27759: Fix selectors incorrectly retain invalid file descriptors. Patch by Mark Williams. +- Issue #28368: Refuse monitoring processes if the child watcher has + no loop attached. + Patch by Vincent Michel. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 17:02:30 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 21:02:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjgzNjgp?= Message-ID: <20161005210213.20553.98822.DC757CA1@psf.io> https://hg.python.org/cpython/rev/83cc47533e4e changeset: 104301:83cc47533e4e parent: 104298:bcee710c42fe parent: 104300:fb6b60955d62 user: Yury Selivanov date: Wed Oct 05 17:02:07 2016 -0400 summary: Merge 3.6 (issue #28368) files: Lib/asyncio/unix_events.py | 23 ++++++++-- Lib/test/test_asyncio/test_subprocess.py | 7 +++ Lib/test/test_asyncio/test_unix_events.py | 14 ++++++- Misc/NEWS | 4 + 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -748,6 +748,7 @@ def __init__(self): self._loop = None + self._callbacks = {} def close(self): self.attach_loop(None) @@ -761,6 +762,12 @@ def attach_loop(self, loop): assert loop is None or isinstance(loop, events.AbstractEventLoop) + if self._loop is not None and loop is None and self._callbacks: + warnings.warn( + 'A loop is being detached ' + 'from a child watcher with pending handlers', + RuntimeWarning) + if self._loop is not None: self._loop.remove_signal_handler(signal.SIGCHLD) @@ -809,10 +816,6 @@ big number of children (O(n) each time SIGCHLD is raised) """ - def __init__(self): - super().__init__() - self._callbacks = {} - def close(self): self._callbacks.clear() super().close() @@ -824,6 +827,11 @@ pass def add_child_handler(self, pid, callback, *args): + if self._loop is None: + raise RuntimeError( + "Cannot add child handler, " + "the child watcher does not have a loop attached") + self._callbacks[pid] = (callback, args) # Prevent a race condition in case the child is already terminated. @@ -888,7 +896,6 @@ """ def __init__(self): super().__init__() - self._callbacks = {} self._lock = threading.Lock() self._zombies = {} self._forks = 0 @@ -920,6 +927,12 @@ def add_child_handler(self, pid, callback, *args): assert self._forks, "Must use the context manager" + + if self._loop is None: + raise RuntimeError( + "Cannot add child handler, " + "the child watcher does not have a loop attached") + with self._lock: try: returncode = self._zombies.pop(pid) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -433,6 +433,13 @@ # the transport was not notified yet self.assertFalse(killed) + # Unlike SafeChildWatcher, FastChildWatcher does not pop the + # callbacks if waitpid() is called elsewhere. Let's clear them + # manually to avoid a warning when the watcher is detached. + if sys.platform != 'win32' and \ + isinstance(self, SubprocessFastWatcherTests): + asyncio.get_child_watcher()._callbacks.clear() + def test_popen_error(self): # Issue #24763: check that the subprocess transport is closed # when BaseSubprocessTransport fails diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -11,6 +11,7 @@ import tempfile import threading import unittest +import warnings from unittest import mock if sys.platform == 'win32': @@ -1391,7 +1392,9 @@ with mock.patch.object( old_loop, "remove_signal_handler") as m_remove_signal_handler: - self.watcher.attach_loop(None) + with self.assertWarnsRegex( + RuntimeWarning, 'A loop is being detached'): + self.watcher.attach_loop(None) m_remove_signal_handler.assert_called_once_with( signal.SIGCHLD) @@ -1463,6 +1466,15 @@ if isinstance(self.watcher, asyncio.FastChildWatcher): self.assertFalse(self.watcher._zombies) + @waitpid_mocks + def test_add_child_handler_with_no_loop_attached(self, m): + callback = mock.Mock() + with self.create_watcher() as watcher: + with self.assertRaisesRegex( + RuntimeError, + 'the child watcher does not have a loop attached'): + watcher.add_child_handler(100, callback) + class SafeChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase): def create_watcher(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -174,6 +174,10 @@ - Issue #28325: Remove vestigal MacOS 9 macurl2path module and its tests. +- Issue #28368: Refuse monitoring processes if the child watcher has + no loop attached. + Patch by Vincent Michel. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 17:02:30 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 21:02:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2328368=29?= Message-ID: <20161005210212.20112.36039.6B5B6075@psf.io> https://hg.python.org/cpython/rev/fb6b60955d62 changeset: 104300:fb6b60955d62 branch: 3.6 parent: 104297:7c36e6fd0232 parent: 104299:2110dcef5892 user: Yury Selivanov date: Wed Oct 05 17:01:01 2016 -0400 summary: Merge 3.5 (issue #28368) files: Lib/asyncio/unix_events.py | 23 ++++++++-- Lib/test/test_asyncio/test_subprocess.py | 7 +++ Lib/test/test_asyncio/test_unix_events.py | 14 ++++++- Misc/NEWS | 4 + 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -748,6 +748,7 @@ def __init__(self): self._loop = None + self._callbacks = {} def close(self): self.attach_loop(None) @@ -761,6 +762,12 @@ def attach_loop(self, loop): assert loop is None or isinstance(loop, events.AbstractEventLoop) + if self._loop is not None and loop is None and self._callbacks: + warnings.warn( + 'A loop is being detached ' + 'from a child watcher with pending handlers', + RuntimeWarning) + if self._loop is not None: self._loop.remove_signal_handler(signal.SIGCHLD) @@ -809,10 +816,6 @@ big number of children (O(n) each time SIGCHLD is raised) """ - def __init__(self): - super().__init__() - self._callbacks = {} - def close(self): self._callbacks.clear() super().close() @@ -824,6 +827,11 @@ pass def add_child_handler(self, pid, callback, *args): + if self._loop is None: + raise RuntimeError( + "Cannot add child handler, " + "the child watcher does not have a loop attached") + self._callbacks[pid] = (callback, args) # Prevent a race condition in case the child is already terminated. @@ -888,7 +896,6 @@ """ def __init__(self): super().__init__() - self._callbacks = {} self._lock = threading.Lock() self._zombies = {} self._forks = 0 @@ -920,6 +927,12 @@ def add_child_handler(self, pid, callback, *args): assert self._forks, "Must use the context manager" + + if self._loop is None: + raise RuntimeError( + "Cannot add child handler, " + "the child watcher does not have a loop attached") + with self._lock: try: returncode = self._zombies.pop(pid) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -433,6 +433,13 @@ # the transport was not notified yet self.assertFalse(killed) + # Unlike SafeChildWatcher, FastChildWatcher does not pop the + # callbacks if waitpid() is called elsewhere. Let's clear them + # manually to avoid a warning when the watcher is detached. + if sys.platform != 'win32' and \ + isinstance(self, SubprocessFastWatcherTests): + asyncio.get_child_watcher()._callbacks.clear() + def test_popen_error(self): # Issue #24763: check that the subprocess transport is closed # when BaseSubprocessTransport fails diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -11,6 +11,7 @@ import tempfile import threading import unittest +import warnings from unittest import mock if sys.platform == 'win32': @@ -1391,7 +1392,9 @@ with mock.patch.object( old_loop, "remove_signal_handler") as m_remove_signal_handler: - self.watcher.attach_loop(None) + with self.assertWarnsRegex( + RuntimeWarning, 'A loop is being detached'): + self.watcher.attach_loop(None) m_remove_signal_handler.assert_called_once_with( signal.SIGCHLD) @@ -1463,6 +1466,15 @@ if isinstance(self.watcher, asyncio.FastChildWatcher): self.assertFalse(self.watcher._zombies) + @waitpid_mocks + def test_add_child_handler_with_no_loop_attached(self, m): + callback = mock.Mock() + with self.create_watcher() as watcher: + with self.assertRaisesRegex( + RuntimeError, + 'the child watcher does not have a loop attached'): + watcher.add_child_handler(100, callback) + class SafeChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase): def create_watcher(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -163,6 +163,10 @@ - Issue #27759: Fix selectors incorrectly retain invalid file descriptors. Patch by Mark Williams. +- Issue #28368: Refuse monitoring processes if the child watcher has no + loop attached. + Patch by Vincent Michel. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 17:50:24 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 21:50:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2328369=29?= Message-ID: <20161005215024.15166.34626.B1A0710C@psf.io> https://hg.python.org/cpython/rev/f3c1d8869dd5 changeset: 104303:f3c1d8869dd5 branch: 3.6 parent: 104300:fb6b60955d62 parent: 104302:2b502f624753 user: Yury Selivanov date: Wed Oct 05 17:49:54 2016 -0400 summary: Merge 3.5 (issue #28369) files: Lib/asyncio/selector_events.py | 127 ++++++--- Lib/asyncio/test_utils.py | 42 ++- Lib/asyncio/unix_events.py | 26 +- Lib/test/test_asyncio/test_base_events.py | 24 +- Lib/test/test_asyncio/test_selector_events.py | 64 ++-- Misc/NEWS | 3 + 6 files changed, 177 insertions(+), 109 deletions(-) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -11,6 +11,7 @@ import functools import socket import warnings +import weakref try: import ssl except ImportError: # pragma: no cover @@ -64,6 +65,7 @@ logger.debug('Using selector: %s', selector.__class__.__name__) self._selector = selector self._make_self_pipe() + self._transports = weakref.WeakValueDictionary() def _make_socket_transport(self, sock, protocol, waiter=None, *, extra=None, server=None): @@ -115,7 +117,7 @@ raise NotImplementedError def _close_self_pipe(self): - self.remove_reader(self._ssock.fileno()) + self._remove_reader(self._ssock.fileno()) self._ssock.close() self._ssock = None self._csock.close() @@ -128,7 +130,7 @@ self._ssock.setblocking(False) self._csock.setblocking(False) self._internal_fds += 1 - self.add_reader(self._ssock.fileno(), self._read_from_self) + self._add_reader(self._ssock.fileno(), self._read_from_self) def _process_self_data(self, data): pass @@ -163,8 +165,8 @@ def _start_serving(self, protocol_factory, sock, sslcontext=None, server=None, backlog=100): - self.add_reader(sock.fileno(), self._accept_connection, - protocol_factory, sock, sslcontext, server, backlog) + self._add_reader(sock.fileno(), self._accept_connection, + protocol_factory, sock, sslcontext, server, backlog) def _accept_connection(self, protocol_factory, sock, sslcontext=None, server=None, backlog=100): @@ -194,7 +196,7 @@ 'exception': exc, 'socket': sock, }) - self.remove_reader(sock.fileno()) + self._remove_reader(sock.fileno()) self.call_later(constants.ACCEPT_RETRY_DELAY, self._start_serving, protocol_factory, sock, sslcontext, server, @@ -244,8 +246,18 @@ context['transport'] = transport self.call_exception_handler(context) - def add_reader(self, fd, callback, *args): - """Add a reader callback.""" + def _ensure_fd_no_transport(self, fd): + try: + transport = self._transports[fd] + except KeyError: + pass + else: + if not transport.is_closing(): + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def _add_reader(self, fd, callback, *args): self._check_closed() handle = events.Handle(callback, args, self) try: @@ -260,8 +272,7 @@ if reader is not None: reader.cancel() - def remove_reader(self, fd): - """Remove a reader callback.""" + def _remove_reader(self, fd): if self.is_closed(): return False try: @@ -282,8 +293,7 @@ else: return False - def add_writer(self, fd, callback, *args): - """Add a writer callback..""" + def _add_writer(self, fd, callback, *args): self._check_closed() handle = events.Handle(callback, args, self) try: @@ -298,7 +308,7 @@ if writer is not None: writer.cancel() - def remove_writer(self, fd): + def _remove_writer(self, fd): """Remove a writer callback.""" if self.is_closed(): return False @@ -321,6 +331,26 @@ else: return False + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + def sock_recv(self, sock, n): """Receive data from the socket. @@ -494,17 +524,17 @@ fileobj, (reader, writer) = key.fileobj, key.data if mask & selectors.EVENT_READ and reader is not None: if reader._cancelled: - self.remove_reader(fileobj) + self._remove_reader(fileobj) else: self._add_callback(reader) if mask & selectors.EVENT_WRITE and writer is not None: if writer._cancelled: - self.remove_writer(fileobj) + self._remove_writer(fileobj) else: self._add_callback(writer) def _stop_serving(self, sock): - self.remove_reader(sock.fileno()) + self._remove_reader(sock.fileno()) sock.close() @@ -539,6 +569,7 @@ self._closing = False # Set when close() called. if self._server is not None: self._server._attach() + loop._transports[self._sock_fd] = self def __repr__(self): info = [self.__class__.__name__] @@ -584,10 +615,10 @@ if self._closing: return self._closing = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if not self._buffer: self._conn_lost += 1 - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._loop.call_soon(self._call_connection_lost, None) # On Python 3.3 and older, objects with a destructor part of a reference @@ -619,10 +650,10 @@ return if self._buffer: self._buffer.clear() - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if not self._closing: self._closing = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) self._conn_lost += 1 self._loop.call_soon(self._call_connection_lost, exc) @@ -659,7 +690,7 @@ self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._sock_fd, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -672,7 +703,7 @@ if self._paused: raise RuntimeError('Already paused') self._paused = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if self._loop.get_debug(): logger.debug("%r pauses reading", self) @@ -682,7 +713,7 @@ self._paused = False if self._closing: return - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._loop.get_debug(): logger.debug("%r resumes reading", self) @@ -706,7 +737,7 @@ # We're keeping the connection open so the # protocol can write more, but we still can't # receive more, so remove the reader callback. - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) else: self.close() @@ -739,7 +770,7 @@ if not data: return # Not all was written; register write handler. - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) # Add it to the buffer. self._buffer.extend(data) @@ -755,7 +786,7 @@ except (BlockingIOError, InterruptedError): pass except Exception as exc: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._buffer.clear() self._fatal_error(exc, 'Fatal write error on socket transport') else: @@ -763,7 +794,7 @@ del self._buffer[:n] self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) elif self._eof: @@ -834,19 +865,19 @@ try: self._sock.do_handshake() except ssl.SSLWantReadError: - self._loop.add_reader(self._sock_fd, - self._on_handshake, start_time) + self._loop._add_reader(self._sock_fd, + self._on_handshake, start_time) return except ssl.SSLWantWriteError: - self._loop.add_writer(self._sock_fd, - self._on_handshake, start_time) + self._loop._add_writer(self._sock_fd, + self._on_handshake, start_time) return except BaseException as exc: if self._loop.get_debug(): logger.warning("%r: SSL handshake failed", self, exc_info=True) - self._loop.remove_reader(self._sock_fd) - self._loop.remove_writer(self._sock_fd) + self._loop._remove_reader(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._sock.close() self._wakeup_waiter(exc) if isinstance(exc, Exception): @@ -854,8 +885,8 @@ else: raise - self._loop.remove_reader(self._sock_fd) - self._loop.remove_writer(self._sock_fd) + self._loop._remove_reader(self._sock_fd) + self._loop._remove_writer(self._sock_fd) peercert = self._sock.getpeercert() if not hasattr(self._sslcontext, 'check_hostname'): @@ -883,7 +914,7 @@ self._read_wants_write = False self._write_wants_read = False - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) self._protocol_connected = True self._loop.call_soon(self._protocol.connection_made, self) # only wake up the waiter when connection_made() has been called @@ -905,7 +936,7 @@ if self._paused: raise RuntimeError('Already paused') self._paused = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if self._loop.get_debug(): logger.debug("%r pauses reading", self) @@ -915,7 +946,7 @@ self._paused = False if self._closing: return - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._loop.get_debug(): logger.debug("%r resumes reading", self) @@ -927,7 +958,7 @@ self._write_ready() if self._buffer: - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) try: data = self._sock.recv(self.max_size) @@ -935,8 +966,8 @@ pass except ssl.SSLWantWriteError: self._read_wants_write = True - self._loop.remove_reader(self._sock_fd) - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._remove_reader(self._sock_fd) + self._loop._add_writer(self._sock_fd, self._write_ready) except Exception as exc: self._fatal_error(exc, 'Fatal read error on SSL transport') else: @@ -961,7 +992,7 @@ self._read_ready() if not (self._paused or self._closing): - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._buffer: try: @@ -970,10 +1001,10 @@ n = 0 except ssl.SSLWantReadError: n = 0 - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._write_wants_read = True except Exception as exc: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._buffer.clear() self._fatal_error(exc, 'Fatal write error on SSL transport') return @@ -984,7 +1015,7 @@ self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) @@ -1002,7 +1033,7 @@ return if not self._buffer: - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) # Add it to the buffer. self._buffer.extend(data) @@ -1022,7 +1053,7 @@ self._address = address self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._sock_fd, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -1072,7 +1103,7 @@ self._sock.sendto(data, addr) return except (BlockingIOError, InterruptedError): - self._loop.add_writer(self._sock_fd, self._sendto_ready) + self._loop._add_writer(self._sock_fd, self._sendto_ready) except OSError as exc: self._protocol.error_received(exc) return @@ -1106,6 +1137,6 @@ self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -13,6 +13,8 @@ import threading import time import unittest +import weakref + from unittest import mock from http.server import HTTPServer @@ -300,6 +302,8 @@ self.writers = {} self.reset_counters() + self._transports = weakref.WeakValueDictionary() + def time(self): return self._time @@ -318,10 +322,10 @@ else: # pragma: no cover raise AssertionError("Time generator is not finished") - def add_reader(self, fd, callback, *args): + def _add_reader(self, fd, callback, *args): self.readers[fd] = events.Handle(callback, args, self) - def remove_reader(self, fd): + def _remove_reader(self, fd): self.remove_reader_count[fd] += 1 if fd in self.readers: del self.readers[fd] @@ -337,10 +341,10 @@ assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) - def add_writer(self, fd, callback, *args): + def _add_writer(self, fd, callback, *args): self.writers[fd] = events.Handle(callback, args, self) - def remove_writer(self, fd): + def _remove_writer(self, fd): self.remove_writer_count[fd] += 1 if fd in self.writers: del self.writers[fd] @@ -356,6 +360,36 @@ assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) + def _ensure_fd_no_transport(self, fd): + try: + transport = self._transports[fd] + except KeyError: + pass + else: + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + def reset_counters(self): self.remove_reader_count = collections.defaultdict(int) self.remove_writer_count = collections.defaultdict(int) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -321,7 +321,7 @@ self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._fileno, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -364,15 +364,15 @@ if self._loop.get_debug(): logger.info("%r was closed by peer", self) self._closing = True - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._protocol.eof_received) self._loop.call_soon(self._call_connection_lost, None) def pause_reading(self): - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) def resume_reading(self): - self._loop.add_reader(self._fileno, self._read_ready) + self._loop._add_reader(self._fileno, self._read_ready) def set_protocol(self, protocol): self._protocol = protocol @@ -413,7 +413,7 @@ def _close(self, exc): self._closing = True - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): @@ -458,7 +458,7 @@ # works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.) if is_socket or (is_fifo and not sys.platform.startswith("aix")): # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._fileno, self._read_ready) if waiter is not None: @@ -531,7 +531,7 @@ return elif n > 0: data = memoryview(data)[n:] - self._loop.add_writer(self._fileno, self._write_ready) + self._loop._add_writer(self._fileno, self._write_ready) self._buffer += data self._maybe_pause_protocol() @@ -548,15 +548,15 @@ self._conn_lost += 1 # Remove writer here, _fatal_error() doesn't it # because _buffer is empty. - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._fatal_error(exc, 'Fatal write error on pipe transport') else: if n == len(self._buffer): self._buffer.clear() - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._maybe_resume_protocol() # May append to buffer. if self._closing: - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._call_connection_lost(None) return elif n > 0: @@ -571,7 +571,7 @@ assert self._pipe self._closing = True if not self._buffer: - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, None) def set_protocol(self, protocol): @@ -618,9 +618,9 @@ def _close(self, exc=None): self._closing = True if self._buffer: - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._buffer.clear() - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -1148,10 +1148,10 @@ m_socket.getaddrinfo = socket.getaddrinfo sock = m_socket.socket.return_value - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.add_writer._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._add_writer._is_coroutine = False coro = self.loop.create_connection(asyncio.Protocol, '1.2.3.4', 80) t, p = self.loop.run_until_complete(coro) @@ -1194,10 +1194,10 @@ m_socket.getaddrinfo = socket.getaddrinfo sock = m_socket.socket.return_value - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.add_writer._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._add_writer._is_coroutine = False for service, port in ('http', 80), (b'http', 80): coro = self.loop.create_connection(asyncio.Protocol, @@ -1614,8 +1614,8 @@ m_socket.getaddrinfo = getaddrinfo m_socket.socket.return_value.bind = bind = mock.Mock() - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False reuseport_supported = hasattr(socket, 'SO_REUSEPORT') coro = self.loop.create_datagram_endpoint( @@ -1646,13 +1646,13 @@ sock = mock.Mock() sock.fileno.return_value = 10 sock.accept.side_effect = OSError(errno.EMFILE, 'Too many open files') - self.loop.remove_reader = mock.Mock() + self.loop._remove_reader = mock.Mock() self.loop.call_later = mock.Mock() self.loop._accept_connection(MyProto, sock) self.assertTrue(m_log.error.called) self.assertFalse(sock.close.called) - self.loop.remove_reader.assert_called_with(10) + self.loop._remove_reader.assert_called_with(10) self.loop.call_later.assert_called_with(constants.ACCEPT_RETRY_DELAY, # self.loop._start_serving mock.ANY, diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -72,11 +72,11 @@ @unittest.skipIf(ssl is None, 'No ssl module') def test_make_ssl_transport(self): m = mock.Mock() - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.remove_reader = mock.Mock() - self.loop.remove_writer = mock.Mock() + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._remove_reader = mock.Mock() + self.loop._remove_writer = mock.Mock() waiter = asyncio.Future(loop=self.loop) with test_utils.disable_logger(): transport = self.loop._make_ssl_transport( @@ -119,7 +119,7 @@ ssock.fileno.return_value = 7 csock = self.loop._csock csock.fileno.return_value = 1 - remove_reader = self.loop.remove_reader = mock.Mock() + remove_reader = self.loop._remove_reader = mock.Mock() self.loop._selector.close() self.loop._selector = selector = mock.Mock() @@ -651,12 +651,12 @@ reader = mock.Mock() reader.cancelled = True - self.loop.remove_reader = mock.Mock() + self.loop._remove_reader = mock.Mock() self.loop._process_events( [(selectors.SelectorKey( 1, 1, selectors.EVENT_READ, (reader, None)), selectors.EVENT_READ)]) - self.loop.remove_reader.assert_called_with(1) + self.loop._remove_reader.assert_called_with(1) def test_process_events_write(self): writer = mock.Mock() @@ -672,13 +672,13 @@ def test_process_events_write_cancelled(self): writer = mock.Mock() writer.cancelled = True - self.loop.remove_writer = mock.Mock() + self.loop._remove_writer = mock.Mock() self.loop._process_events( [(selectors.SelectorKey(1, 1, selectors.EVENT_WRITE, (None, writer)), selectors.EVENT_WRITE)]) - self.loop.remove_writer.assert_called_with(1) + self.loop._remove_writer.assert_called_with(1) def test_accept_connection_multiple(self): sock = mock.Mock() @@ -747,8 +747,8 @@ def test_force_close(self): tr = self.create_transport() tr._buffer.extend(b'1') - self.loop.add_reader(7, mock.sentinel) - self.loop.add_writer(7, mock.sentinel) + self.loop._add_reader(7, mock.sentinel) + self.loop._add_writer(7, mock.sentinel) tr._force_close(None) self.assertTrue(tr.is_closing()) @@ -1037,7 +1037,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.assertTrue(self.sock.send.called) self.assertFalse(self.loop.writers) @@ -1049,7 +1049,7 @@ transport = self.socket_transport() transport._closing = True transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.assertTrue(self.sock.send.called) self.assertFalse(self.loop.writers) @@ -1067,7 +1067,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) self.assertEqual(list_to_buffer([b'ta']), transport._buffer) @@ -1078,7 +1078,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) self.assertEqual(list_to_buffer([b'data']), transport._buffer) @@ -1088,7 +1088,7 @@ transport = self.socket_transport() transport._buffer = list_to_buffer([b'data1', b'data2']) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) @@ -1130,7 +1130,7 @@ @mock.patch('asyncio.base_events.logger') def test_transport_close_remove_writer(self, m_log): - remove_writer = self.loop.remove_writer = mock.Mock() + remove_writer = self.loop._remove_writer = mock.Mock() transport = self.socket_transport() transport.close() @@ -1288,7 +1288,7 @@ self.assertEqual((b'data',), self.protocol.data_received.call_args[0]) def test_read_ready_write_wants_read(self): - self.loop.add_writer = mock.Mock() + self.loop._add_writer = mock.Mock() self.sslsock.recv.side_effect = BlockingIOError transport = self._make_one() transport._write_wants_read = True @@ -1298,7 +1298,7 @@ self.assertFalse(transport._write_wants_read) transport._write_ready.assert_called_with() - self.loop.add_writer.assert_called_with( + self.loop._add_writer.assert_called_with( transport._sock_fd, transport._write_ready) def test_read_ready_recv_eof(self): @@ -1333,16 +1333,16 @@ self.assertFalse(self.protocol.data_received.called) def test_read_ready_recv_write(self): - self.loop.remove_reader = mock.Mock() - self.loop.add_writer = mock.Mock() + self.loop._remove_reader = mock.Mock() + self.loop._add_writer = mock.Mock() self.sslsock.recv.side_effect = ssl.SSLWantWriteError transport = self._make_one() transport._read_ready() self.assertFalse(self.protocol.data_received.called) self.assertTrue(transport._read_wants_write) - self.loop.remove_reader.assert_called_with(transport._sock_fd) - self.loop.add_writer.assert_called_with( + self.loop._remove_reader.assert_called_with(transport._sock_fd) + self.loop._add_writer.assert_called_with( transport._sock_fd, transport._write_ready) def test_read_ready_recv_exc(self): @@ -1419,12 +1419,12 @@ transport = self._make_one() transport._buffer = list_to_buffer([b'data']) - self.loop.remove_writer = mock.Mock() + self.loop._remove_writer = mock.Mock() self.sslsock.send.side_effect = ssl.SSLWantReadError transport._write_ready() self.assertFalse(self.protocol.data_received.called) self.assertTrue(transport._write_wants_read) - self.loop.remove_writer.assert_called_with(transport._sock_fd) + self.loop._remove_writer.assert_called_with(transport._sock_fd) def test_write_ready_send_exc(self): err = self.sslsock.send.side_effect = OSError() @@ -1439,7 +1439,7 @@ self.assertEqual(list_to_buffer(), transport._buffer) def test_write_ready_read_wants_write(self): - self.loop.add_reader = mock.Mock() + self.loop._add_reader = mock.Mock() self.sslsock.send.side_effect = BlockingIOError transport = self._make_one() transport._read_wants_write = True @@ -1448,7 +1448,7 @@ self.assertFalse(transport._read_wants_write) transport._read_ready.assert_called_with() - self.loop.add_reader.assert_called_with( + self.loop._add_reader.assert_called_with( transport._sock_fd, transport._read_ready) def test_write_eof(self): @@ -1699,7 +1699,7 @@ transport = self.datagram_transport() transport._buffer.append((data, ('0.0.0.0', 12345))) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.assertTrue(self.sock.sendto.called) self.assertEqual( @@ -1713,7 +1713,7 @@ transport = self.datagram_transport() transport._closing = True transport._buffer.append((data, ())) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.sock.sendto.assert_called_with(data, ()) self.assertFalse(self.loop.writers) @@ -1722,7 +1722,7 @@ def test_sendto_ready_no_data(self): transport = self.datagram_transport() - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.assertFalse(self.sock.sendto.called) self.assertFalse(self.loop.writers) @@ -1732,7 +1732,7 @@ transport = self.datagram_transport() transport._buffer.extend([(b'data1', ()), (b'data2', ())]) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.loop.assert_writer(7, transport._sendto_ready) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -167,6 +167,9 @@ loop attached. Patch by Vincent Michel. +- Issue #28369: Raise RuntimeError when transport's FD is used with + add_reader, add_writer, etc. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 17:50:24 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 21:50:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjgzNjkp?= Message-ID: <20161005215024.82187.25709.D716B970@psf.io> https://hg.python.org/cpython/rev/745e0ff513c2 changeset: 104304:745e0ff513c2 parent: 104301:83cc47533e4e parent: 104303:f3c1d8869dd5 user: Yury Selivanov date: Wed Oct 05 17:50:19 2016 -0400 summary: Merge 3.6 (issue #28369) files: Lib/asyncio/selector_events.py | 127 ++++++--- Lib/asyncio/test_utils.py | 42 ++- Lib/asyncio/unix_events.py | 26 +- Lib/test/test_asyncio/test_base_events.py | 24 +- Lib/test/test_asyncio/test_selector_events.py | 64 ++-- Misc/NEWS | 3 + 6 files changed, 177 insertions(+), 109 deletions(-) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -11,6 +11,7 @@ import functools import socket import warnings +import weakref try: import ssl except ImportError: # pragma: no cover @@ -64,6 +65,7 @@ logger.debug('Using selector: %s', selector.__class__.__name__) self._selector = selector self._make_self_pipe() + self._transports = weakref.WeakValueDictionary() def _make_socket_transport(self, sock, protocol, waiter=None, *, extra=None, server=None): @@ -115,7 +117,7 @@ raise NotImplementedError def _close_self_pipe(self): - self.remove_reader(self._ssock.fileno()) + self._remove_reader(self._ssock.fileno()) self._ssock.close() self._ssock = None self._csock.close() @@ -128,7 +130,7 @@ self._ssock.setblocking(False) self._csock.setblocking(False) self._internal_fds += 1 - self.add_reader(self._ssock.fileno(), self._read_from_self) + self._add_reader(self._ssock.fileno(), self._read_from_self) def _process_self_data(self, data): pass @@ -163,8 +165,8 @@ def _start_serving(self, protocol_factory, sock, sslcontext=None, server=None, backlog=100): - self.add_reader(sock.fileno(), self._accept_connection, - protocol_factory, sock, sslcontext, server, backlog) + self._add_reader(sock.fileno(), self._accept_connection, + protocol_factory, sock, sslcontext, server, backlog) def _accept_connection(self, protocol_factory, sock, sslcontext=None, server=None, backlog=100): @@ -194,7 +196,7 @@ 'exception': exc, 'socket': sock, }) - self.remove_reader(sock.fileno()) + self._remove_reader(sock.fileno()) self.call_later(constants.ACCEPT_RETRY_DELAY, self._start_serving, protocol_factory, sock, sslcontext, server, @@ -244,8 +246,18 @@ context['transport'] = transport self.call_exception_handler(context) - def add_reader(self, fd, callback, *args): - """Add a reader callback.""" + def _ensure_fd_no_transport(self, fd): + try: + transport = self._transports[fd] + except KeyError: + pass + else: + if not transport.is_closing(): + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def _add_reader(self, fd, callback, *args): self._check_closed() handle = events.Handle(callback, args, self) try: @@ -260,8 +272,7 @@ if reader is not None: reader.cancel() - def remove_reader(self, fd): - """Remove a reader callback.""" + def _remove_reader(self, fd): if self.is_closed(): return False try: @@ -282,8 +293,7 @@ else: return False - def add_writer(self, fd, callback, *args): - """Add a writer callback..""" + def _add_writer(self, fd, callback, *args): self._check_closed() handle = events.Handle(callback, args, self) try: @@ -298,7 +308,7 @@ if writer is not None: writer.cancel() - def remove_writer(self, fd): + def _remove_writer(self, fd): """Remove a writer callback.""" if self.is_closed(): return False @@ -321,6 +331,26 @@ else: return False + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + def sock_recv(self, sock, n): """Receive data from the socket. @@ -494,17 +524,17 @@ fileobj, (reader, writer) = key.fileobj, key.data if mask & selectors.EVENT_READ and reader is not None: if reader._cancelled: - self.remove_reader(fileobj) + self._remove_reader(fileobj) else: self._add_callback(reader) if mask & selectors.EVENT_WRITE and writer is not None: if writer._cancelled: - self.remove_writer(fileobj) + self._remove_writer(fileobj) else: self._add_callback(writer) def _stop_serving(self, sock): - self.remove_reader(sock.fileno()) + self._remove_reader(sock.fileno()) sock.close() @@ -539,6 +569,7 @@ self._closing = False # Set when close() called. if self._server is not None: self._server._attach() + loop._transports[self._sock_fd] = self def __repr__(self): info = [self.__class__.__name__] @@ -584,10 +615,10 @@ if self._closing: return self._closing = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if not self._buffer: self._conn_lost += 1 - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._loop.call_soon(self._call_connection_lost, None) # On Python 3.3 and older, objects with a destructor part of a reference @@ -619,10 +650,10 @@ return if self._buffer: self._buffer.clear() - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if not self._closing: self._closing = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) self._conn_lost += 1 self._loop.call_soon(self._call_connection_lost, exc) @@ -659,7 +690,7 @@ self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._sock_fd, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -672,7 +703,7 @@ if self._paused: raise RuntimeError('Already paused') self._paused = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if self._loop.get_debug(): logger.debug("%r pauses reading", self) @@ -682,7 +713,7 @@ self._paused = False if self._closing: return - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._loop.get_debug(): logger.debug("%r resumes reading", self) @@ -706,7 +737,7 @@ # We're keeping the connection open so the # protocol can write more, but we still can't # receive more, so remove the reader callback. - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) else: self.close() @@ -739,7 +770,7 @@ if not data: return # Not all was written; register write handler. - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) # Add it to the buffer. self._buffer.extend(data) @@ -755,7 +786,7 @@ except (BlockingIOError, InterruptedError): pass except Exception as exc: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._buffer.clear() self._fatal_error(exc, 'Fatal write error on socket transport') else: @@ -763,7 +794,7 @@ del self._buffer[:n] self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) elif self._eof: @@ -834,19 +865,19 @@ try: self._sock.do_handshake() except ssl.SSLWantReadError: - self._loop.add_reader(self._sock_fd, - self._on_handshake, start_time) + self._loop._add_reader(self._sock_fd, + self._on_handshake, start_time) return except ssl.SSLWantWriteError: - self._loop.add_writer(self._sock_fd, - self._on_handshake, start_time) + self._loop._add_writer(self._sock_fd, + self._on_handshake, start_time) return except BaseException as exc: if self._loop.get_debug(): logger.warning("%r: SSL handshake failed", self, exc_info=True) - self._loop.remove_reader(self._sock_fd) - self._loop.remove_writer(self._sock_fd) + self._loop._remove_reader(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._sock.close() self._wakeup_waiter(exc) if isinstance(exc, Exception): @@ -854,8 +885,8 @@ else: raise - self._loop.remove_reader(self._sock_fd) - self._loop.remove_writer(self._sock_fd) + self._loop._remove_reader(self._sock_fd) + self._loop._remove_writer(self._sock_fd) peercert = self._sock.getpeercert() if not hasattr(self._sslcontext, 'check_hostname'): @@ -883,7 +914,7 @@ self._read_wants_write = False self._write_wants_read = False - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) self._protocol_connected = True self._loop.call_soon(self._protocol.connection_made, self) # only wake up the waiter when connection_made() has been called @@ -905,7 +936,7 @@ if self._paused: raise RuntimeError('Already paused') self._paused = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if self._loop.get_debug(): logger.debug("%r pauses reading", self) @@ -915,7 +946,7 @@ self._paused = False if self._closing: return - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._loop.get_debug(): logger.debug("%r resumes reading", self) @@ -927,7 +958,7 @@ self._write_ready() if self._buffer: - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) try: data = self._sock.recv(self.max_size) @@ -935,8 +966,8 @@ pass except ssl.SSLWantWriteError: self._read_wants_write = True - self._loop.remove_reader(self._sock_fd) - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._remove_reader(self._sock_fd) + self._loop._add_writer(self._sock_fd, self._write_ready) except Exception as exc: self._fatal_error(exc, 'Fatal read error on SSL transport') else: @@ -961,7 +992,7 @@ self._read_ready() if not (self._paused or self._closing): - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._buffer: try: @@ -970,10 +1001,10 @@ n = 0 except ssl.SSLWantReadError: n = 0 - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._write_wants_read = True except Exception as exc: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._buffer.clear() self._fatal_error(exc, 'Fatal write error on SSL transport') return @@ -984,7 +1015,7 @@ self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) @@ -1002,7 +1033,7 @@ return if not self._buffer: - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) # Add it to the buffer. self._buffer.extend(data) @@ -1022,7 +1053,7 @@ self._address = address self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._sock_fd, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -1072,7 +1103,7 @@ self._sock.sendto(data, addr) return except (BlockingIOError, InterruptedError): - self._loop.add_writer(self._sock_fd, self._sendto_ready) + self._loop._add_writer(self._sock_fd, self._sendto_ready) except OSError as exc: self._protocol.error_received(exc) return @@ -1106,6 +1137,6 @@ self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -13,6 +13,8 @@ import threading import time import unittest +import weakref + from unittest import mock from http.server import HTTPServer @@ -300,6 +302,8 @@ self.writers = {} self.reset_counters() + self._transports = weakref.WeakValueDictionary() + def time(self): return self._time @@ -318,10 +322,10 @@ else: # pragma: no cover raise AssertionError("Time generator is not finished") - def add_reader(self, fd, callback, *args): + def _add_reader(self, fd, callback, *args): self.readers[fd] = events.Handle(callback, args, self) - def remove_reader(self, fd): + def _remove_reader(self, fd): self.remove_reader_count[fd] += 1 if fd in self.readers: del self.readers[fd] @@ -337,10 +341,10 @@ assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) - def add_writer(self, fd, callback, *args): + def _add_writer(self, fd, callback, *args): self.writers[fd] = events.Handle(callback, args, self) - def remove_writer(self, fd): + def _remove_writer(self, fd): self.remove_writer_count[fd] += 1 if fd in self.writers: del self.writers[fd] @@ -356,6 +360,36 @@ assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) + def _ensure_fd_no_transport(self, fd): + try: + transport = self._transports[fd] + except KeyError: + pass + else: + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + def reset_counters(self): self.remove_reader_count = collections.defaultdict(int) self.remove_writer_count = collections.defaultdict(int) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -321,7 +321,7 @@ self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._fileno, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -364,15 +364,15 @@ if self._loop.get_debug(): logger.info("%r was closed by peer", self) self._closing = True - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._protocol.eof_received) self._loop.call_soon(self._call_connection_lost, None) def pause_reading(self): - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) def resume_reading(self): - self._loop.add_reader(self._fileno, self._read_ready) + self._loop._add_reader(self._fileno, self._read_ready) def set_protocol(self, protocol): self._protocol = protocol @@ -413,7 +413,7 @@ def _close(self, exc): self._closing = True - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): @@ -458,7 +458,7 @@ # works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.) if is_socket or (is_fifo and not sys.platform.startswith("aix")): # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._fileno, self._read_ready) if waiter is not None: @@ -531,7 +531,7 @@ return elif n > 0: data = memoryview(data)[n:] - self._loop.add_writer(self._fileno, self._write_ready) + self._loop._add_writer(self._fileno, self._write_ready) self._buffer += data self._maybe_pause_protocol() @@ -548,15 +548,15 @@ self._conn_lost += 1 # Remove writer here, _fatal_error() doesn't it # because _buffer is empty. - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._fatal_error(exc, 'Fatal write error on pipe transport') else: if n == len(self._buffer): self._buffer.clear() - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._maybe_resume_protocol() # May append to buffer. if self._closing: - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._call_connection_lost(None) return elif n > 0: @@ -571,7 +571,7 @@ assert self._pipe self._closing = True if not self._buffer: - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, None) def set_protocol(self, protocol): @@ -618,9 +618,9 @@ def _close(self, exc=None): self._closing = True if self._buffer: - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._buffer.clear() - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -1148,10 +1148,10 @@ m_socket.getaddrinfo = socket.getaddrinfo sock = m_socket.socket.return_value - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.add_writer._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._add_writer._is_coroutine = False coro = self.loop.create_connection(asyncio.Protocol, '1.2.3.4', 80) t, p = self.loop.run_until_complete(coro) @@ -1194,10 +1194,10 @@ m_socket.getaddrinfo = socket.getaddrinfo sock = m_socket.socket.return_value - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.add_writer._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._add_writer._is_coroutine = False for service, port in ('http', 80), (b'http', 80): coro = self.loop.create_connection(asyncio.Protocol, @@ -1614,8 +1614,8 @@ m_socket.getaddrinfo = getaddrinfo m_socket.socket.return_value.bind = bind = mock.Mock() - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False reuseport_supported = hasattr(socket, 'SO_REUSEPORT') coro = self.loop.create_datagram_endpoint( @@ -1646,13 +1646,13 @@ sock = mock.Mock() sock.fileno.return_value = 10 sock.accept.side_effect = OSError(errno.EMFILE, 'Too many open files') - self.loop.remove_reader = mock.Mock() + self.loop._remove_reader = mock.Mock() self.loop.call_later = mock.Mock() self.loop._accept_connection(MyProto, sock) self.assertTrue(m_log.error.called) self.assertFalse(sock.close.called) - self.loop.remove_reader.assert_called_with(10) + self.loop._remove_reader.assert_called_with(10) self.loop.call_later.assert_called_with(constants.ACCEPT_RETRY_DELAY, # self.loop._start_serving mock.ANY, diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -72,11 +72,11 @@ @unittest.skipIf(ssl is None, 'No ssl module') def test_make_ssl_transport(self): m = mock.Mock() - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.remove_reader = mock.Mock() - self.loop.remove_writer = mock.Mock() + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._remove_reader = mock.Mock() + self.loop._remove_writer = mock.Mock() waiter = asyncio.Future(loop=self.loop) with test_utils.disable_logger(): transport = self.loop._make_ssl_transport( @@ -119,7 +119,7 @@ ssock.fileno.return_value = 7 csock = self.loop._csock csock.fileno.return_value = 1 - remove_reader = self.loop.remove_reader = mock.Mock() + remove_reader = self.loop._remove_reader = mock.Mock() self.loop._selector.close() self.loop._selector = selector = mock.Mock() @@ -651,12 +651,12 @@ reader = mock.Mock() reader.cancelled = True - self.loop.remove_reader = mock.Mock() + self.loop._remove_reader = mock.Mock() self.loop._process_events( [(selectors.SelectorKey( 1, 1, selectors.EVENT_READ, (reader, None)), selectors.EVENT_READ)]) - self.loop.remove_reader.assert_called_with(1) + self.loop._remove_reader.assert_called_with(1) def test_process_events_write(self): writer = mock.Mock() @@ -672,13 +672,13 @@ def test_process_events_write_cancelled(self): writer = mock.Mock() writer.cancelled = True - self.loop.remove_writer = mock.Mock() + self.loop._remove_writer = mock.Mock() self.loop._process_events( [(selectors.SelectorKey(1, 1, selectors.EVENT_WRITE, (None, writer)), selectors.EVENT_WRITE)]) - self.loop.remove_writer.assert_called_with(1) + self.loop._remove_writer.assert_called_with(1) def test_accept_connection_multiple(self): sock = mock.Mock() @@ -747,8 +747,8 @@ def test_force_close(self): tr = self.create_transport() tr._buffer.extend(b'1') - self.loop.add_reader(7, mock.sentinel) - self.loop.add_writer(7, mock.sentinel) + self.loop._add_reader(7, mock.sentinel) + self.loop._add_writer(7, mock.sentinel) tr._force_close(None) self.assertTrue(tr.is_closing()) @@ -1037,7 +1037,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.assertTrue(self.sock.send.called) self.assertFalse(self.loop.writers) @@ -1049,7 +1049,7 @@ transport = self.socket_transport() transport._closing = True transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.assertTrue(self.sock.send.called) self.assertFalse(self.loop.writers) @@ -1067,7 +1067,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) self.assertEqual(list_to_buffer([b'ta']), transport._buffer) @@ -1078,7 +1078,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) self.assertEqual(list_to_buffer([b'data']), transport._buffer) @@ -1088,7 +1088,7 @@ transport = self.socket_transport() transport._buffer = list_to_buffer([b'data1', b'data2']) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) @@ -1130,7 +1130,7 @@ @mock.patch('asyncio.base_events.logger') def test_transport_close_remove_writer(self, m_log): - remove_writer = self.loop.remove_writer = mock.Mock() + remove_writer = self.loop._remove_writer = mock.Mock() transport = self.socket_transport() transport.close() @@ -1288,7 +1288,7 @@ self.assertEqual((b'data',), self.protocol.data_received.call_args[0]) def test_read_ready_write_wants_read(self): - self.loop.add_writer = mock.Mock() + self.loop._add_writer = mock.Mock() self.sslsock.recv.side_effect = BlockingIOError transport = self._make_one() transport._write_wants_read = True @@ -1298,7 +1298,7 @@ self.assertFalse(transport._write_wants_read) transport._write_ready.assert_called_with() - self.loop.add_writer.assert_called_with( + self.loop._add_writer.assert_called_with( transport._sock_fd, transport._write_ready) def test_read_ready_recv_eof(self): @@ -1333,16 +1333,16 @@ self.assertFalse(self.protocol.data_received.called) def test_read_ready_recv_write(self): - self.loop.remove_reader = mock.Mock() - self.loop.add_writer = mock.Mock() + self.loop._remove_reader = mock.Mock() + self.loop._add_writer = mock.Mock() self.sslsock.recv.side_effect = ssl.SSLWantWriteError transport = self._make_one() transport._read_ready() self.assertFalse(self.protocol.data_received.called) self.assertTrue(transport._read_wants_write) - self.loop.remove_reader.assert_called_with(transport._sock_fd) - self.loop.add_writer.assert_called_with( + self.loop._remove_reader.assert_called_with(transport._sock_fd) + self.loop._add_writer.assert_called_with( transport._sock_fd, transport._write_ready) def test_read_ready_recv_exc(self): @@ -1419,12 +1419,12 @@ transport = self._make_one() transport._buffer = list_to_buffer([b'data']) - self.loop.remove_writer = mock.Mock() + self.loop._remove_writer = mock.Mock() self.sslsock.send.side_effect = ssl.SSLWantReadError transport._write_ready() self.assertFalse(self.protocol.data_received.called) self.assertTrue(transport._write_wants_read) - self.loop.remove_writer.assert_called_with(transport._sock_fd) + self.loop._remove_writer.assert_called_with(transport._sock_fd) def test_write_ready_send_exc(self): err = self.sslsock.send.side_effect = OSError() @@ -1439,7 +1439,7 @@ self.assertEqual(list_to_buffer(), transport._buffer) def test_write_ready_read_wants_write(self): - self.loop.add_reader = mock.Mock() + self.loop._add_reader = mock.Mock() self.sslsock.send.side_effect = BlockingIOError transport = self._make_one() transport._read_wants_write = True @@ -1448,7 +1448,7 @@ self.assertFalse(transport._read_wants_write) transport._read_ready.assert_called_with() - self.loop.add_reader.assert_called_with( + self.loop._add_reader.assert_called_with( transport._sock_fd, transport._read_ready) def test_write_eof(self): @@ -1699,7 +1699,7 @@ transport = self.datagram_transport() transport._buffer.append((data, ('0.0.0.0', 12345))) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.assertTrue(self.sock.sendto.called) self.assertEqual( @@ -1713,7 +1713,7 @@ transport = self.datagram_transport() transport._closing = True transport._buffer.append((data, ())) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.sock.sendto.assert_called_with(data, ()) self.assertFalse(self.loop.writers) @@ -1722,7 +1722,7 @@ def test_sendto_ready_no_data(self): transport = self.datagram_transport() - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.assertFalse(self.sock.sendto.called) self.assertFalse(self.loop.writers) @@ -1732,7 +1732,7 @@ transport = self.datagram_transport() transport._buffer.extend([(b'data1', ()), (b'data2', ())]) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.loop.assert_writer(7, transport._sendto_ready) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -178,6 +178,9 @@ no loop attached. Patch by Vincent Michel. +- Issue #28369: Raise RuntimeError when transport's FD is used with + add_reader, add_writer, etc. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 17:50:24 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 21:50:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzY5?= =?utf-8?q?=3A_Raise_an_error_when_transport=27s_FD_is_used_with_add=5Frea?= =?utf-8?q?der?= Message-ID: <20161005215024.82459.5977.0D7541F7@psf.io> https://hg.python.org/cpython/rev/2b502f624753 changeset: 104302:2b502f624753 branch: 3.5 parent: 104299:2110dcef5892 user: Yury Selivanov date: Wed Oct 05 17:48:59 2016 -0400 summary: Issue #28369: Raise an error when transport's FD is used with add_reader files: Lib/asyncio/selector_events.py | 127 ++++++--- Lib/asyncio/test_utils.py | 42 ++- Lib/asyncio/unix_events.py | 26 +- Lib/test/test_asyncio/test_base_events.py | 24 +- Lib/test/test_asyncio/test_selector_events.py | 64 ++-- Misc/NEWS | 3 + 6 files changed, 177 insertions(+), 109 deletions(-) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -11,6 +11,7 @@ import functools import socket import warnings +import weakref try: import ssl except ImportError: # pragma: no cover @@ -64,6 +65,7 @@ logger.debug('Using selector: %s', selector.__class__.__name__) self._selector = selector self._make_self_pipe() + self._transports = weakref.WeakValueDictionary() def _make_socket_transport(self, sock, protocol, waiter=None, *, extra=None, server=None): @@ -115,7 +117,7 @@ raise NotImplementedError def _close_self_pipe(self): - self.remove_reader(self._ssock.fileno()) + self._remove_reader(self._ssock.fileno()) self._ssock.close() self._ssock = None self._csock.close() @@ -128,7 +130,7 @@ self._ssock.setblocking(False) self._csock.setblocking(False) self._internal_fds += 1 - self.add_reader(self._ssock.fileno(), self._read_from_self) + self._add_reader(self._ssock.fileno(), self._read_from_self) def _process_self_data(self, data): pass @@ -163,8 +165,8 @@ def _start_serving(self, protocol_factory, sock, sslcontext=None, server=None, backlog=100): - self.add_reader(sock.fileno(), self._accept_connection, - protocol_factory, sock, sslcontext, server, backlog) + self._add_reader(sock.fileno(), self._accept_connection, + protocol_factory, sock, sslcontext, server, backlog) def _accept_connection(self, protocol_factory, sock, sslcontext=None, server=None, backlog=100): @@ -194,7 +196,7 @@ 'exception': exc, 'socket': sock, }) - self.remove_reader(sock.fileno()) + self._remove_reader(sock.fileno()) self.call_later(constants.ACCEPT_RETRY_DELAY, self._start_serving, protocol_factory, sock, sslcontext, server, @@ -244,8 +246,18 @@ context['transport'] = transport self.call_exception_handler(context) - def add_reader(self, fd, callback, *args): - """Add a reader callback.""" + def _ensure_fd_no_transport(self, fd): + try: + transport = self._transports[fd] + except KeyError: + pass + else: + if not transport.is_closing(): + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def _add_reader(self, fd, callback, *args): self._check_closed() handle = events.Handle(callback, args, self) try: @@ -260,8 +272,7 @@ if reader is not None: reader.cancel() - def remove_reader(self, fd): - """Remove a reader callback.""" + def _remove_reader(self, fd): if self.is_closed(): return False try: @@ -282,8 +293,7 @@ else: return False - def add_writer(self, fd, callback, *args): - """Add a writer callback..""" + def _add_writer(self, fd, callback, *args): self._check_closed() handle = events.Handle(callback, args, self) try: @@ -298,7 +308,7 @@ if writer is not None: writer.cancel() - def remove_writer(self, fd): + def _remove_writer(self, fd): """Remove a writer callback.""" if self.is_closed(): return False @@ -321,6 +331,26 @@ else: return False + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + def sock_recv(self, sock, n): """Receive data from the socket. @@ -494,17 +524,17 @@ fileobj, (reader, writer) = key.fileobj, key.data if mask & selectors.EVENT_READ and reader is not None: if reader._cancelled: - self.remove_reader(fileobj) + self._remove_reader(fileobj) else: self._add_callback(reader) if mask & selectors.EVENT_WRITE and writer is not None: if writer._cancelled: - self.remove_writer(fileobj) + self._remove_writer(fileobj) else: self._add_callback(writer) def _stop_serving(self, sock): - self.remove_reader(sock.fileno()) + self._remove_reader(sock.fileno()) sock.close() @@ -539,6 +569,7 @@ self._closing = False # Set when close() called. if self._server is not None: self._server._attach() + loop._transports[self._sock_fd] = self def __repr__(self): info = [self.__class__.__name__] @@ -584,10 +615,10 @@ if self._closing: return self._closing = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if not self._buffer: self._conn_lost += 1 - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._loop.call_soon(self._call_connection_lost, None) # On Python 3.3 and older, objects with a destructor part of a reference @@ -618,10 +649,10 @@ return if self._buffer: self._buffer.clear() - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if not self._closing: self._closing = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) self._conn_lost += 1 self._loop.call_soon(self._call_connection_lost, exc) @@ -658,7 +689,7 @@ self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._sock_fd, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -671,7 +702,7 @@ if self._paused: raise RuntimeError('Already paused') self._paused = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if self._loop.get_debug(): logger.debug("%r pauses reading", self) @@ -681,7 +712,7 @@ self._paused = False if self._closing: return - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._loop.get_debug(): logger.debug("%r resumes reading", self) @@ -705,7 +736,7 @@ # We're keeping the connection open so the # protocol can write more, but we still can't # receive more, so remove the reader callback. - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) else: self.close() @@ -738,7 +769,7 @@ if not data: return # Not all was written; register write handler. - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) # Add it to the buffer. self._buffer.extend(data) @@ -754,7 +785,7 @@ except (BlockingIOError, InterruptedError): pass except Exception as exc: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._buffer.clear() self._fatal_error(exc, 'Fatal write error on socket transport') else: @@ -762,7 +793,7 @@ del self._buffer[:n] self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) elif self._eof: @@ -833,19 +864,19 @@ try: self._sock.do_handshake() except ssl.SSLWantReadError: - self._loop.add_reader(self._sock_fd, - self._on_handshake, start_time) + self._loop._add_reader(self._sock_fd, + self._on_handshake, start_time) return except ssl.SSLWantWriteError: - self._loop.add_writer(self._sock_fd, - self._on_handshake, start_time) + self._loop._add_writer(self._sock_fd, + self._on_handshake, start_time) return except BaseException as exc: if self._loop.get_debug(): logger.warning("%r: SSL handshake failed", self, exc_info=True) - self._loop.remove_reader(self._sock_fd) - self._loop.remove_writer(self._sock_fd) + self._loop._remove_reader(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._sock.close() self._wakeup_waiter(exc) if isinstance(exc, Exception): @@ -853,8 +884,8 @@ else: raise - self._loop.remove_reader(self._sock_fd) - self._loop.remove_writer(self._sock_fd) + self._loop._remove_reader(self._sock_fd) + self._loop._remove_writer(self._sock_fd) peercert = self._sock.getpeercert() if not hasattr(self._sslcontext, 'check_hostname'): @@ -882,7 +913,7 @@ self._read_wants_write = False self._write_wants_read = False - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) self._protocol_connected = True self._loop.call_soon(self._protocol.connection_made, self) # only wake up the waiter when connection_made() has been called @@ -904,7 +935,7 @@ if self._paused: raise RuntimeError('Already paused') self._paused = True - self._loop.remove_reader(self._sock_fd) + self._loop._remove_reader(self._sock_fd) if self._loop.get_debug(): logger.debug("%r pauses reading", self) @@ -914,7 +945,7 @@ self._paused = False if self._closing: return - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._loop.get_debug(): logger.debug("%r resumes reading", self) @@ -926,7 +957,7 @@ self._write_ready() if self._buffer: - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) try: data = self._sock.recv(self.max_size) @@ -934,8 +965,8 @@ pass except ssl.SSLWantWriteError: self._read_wants_write = True - self._loop.remove_reader(self._sock_fd) - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._remove_reader(self._sock_fd) + self._loop._add_writer(self._sock_fd, self._write_ready) except Exception as exc: self._fatal_error(exc, 'Fatal read error on SSL transport') else: @@ -960,7 +991,7 @@ self._read_ready() if not (self._paused or self._closing): - self._loop.add_reader(self._sock_fd, self._read_ready) + self._loop._add_reader(self._sock_fd, self._read_ready) if self._buffer: try: @@ -969,10 +1000,10 @@ n = 0 except ssl.SSLWantReadError: n = 0 - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._write_wants_read = True except Exception as exc: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) self._buffer.clear() self._fatal_error(exc, 'Fatal write error on SSL transport') return @@ -983,7 +1014,7 @@ self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) @@ -1001,7 +1032,7 @@ return if not self._buffer: - self._loop.add_writer(self._sock_fd, self._write_ready) + self._loop._add_writer(self._sock_fd, self._write_ready) # Add it to the buffer. self._buffer.extend(data) @@ -1021,7 +1052,7 @@ self._address = address self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._sock_fd, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -1071,7 +1102,7 @@ self._sock.sendto(data, addr) return except (BlockingIOError, InterruptedError): - self._loop.add_writer(self._sock_fd, self._sendto_ready) + self._loop._add_writer(self._sock_fd, self._sendto_ready) except OSError as exc: self._protocol.error_received(exc) return @@ -1105,6 +1136,6 @@ self._maybe_resume_protocol() # May append to buffer. if not self._buffer: - self._loop.remove_writer(self._sock_fd) + self._loop._remove_writer(self._sock_fd) if self._closing: self._call_connection_lost(None) diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -13,6 +13,8 @@ import threading import time import unittest +import weakref + from unittest import mock from http.server import HTTPServer @@ -300,6 +302,8 @@ self.writers = {} self.reset_counters() + self._transports = weakref.WeakValueDictionary() + def time(self): return self._time @@ -318,10 +322,10 @@ else: # pragma: no cover raise AssertionError("Time generator is not finished") - def add_reader(self, fd, callback, *args): + def _add_reader(self, fd, callback, *args): self.readers[fd] = events.Handle(callback, args, self) - def remove_reader(self, fd): + def _remove_reader(self, fd): self.remove_reader_count[fd] += 1 if fd in self.readers: del self.readers[fd] @@ -337,10 +341,10 @@ assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) - def add_writer(self, fd, callback, *args): + def _add_writer(self, fd, callback, *args): self.writers[fd] = events.Handle(callback, args, self) - def remove_writer(self, fd): + def _remove_writer(self, fd): self.remove_writer_count[fd] += 1 if fd in self.writers: del self.writers[fd] @@ -356,6 +360,36 @@ assert handle._args == args, '{!r} != {!r}'.format( handle._args, args) + def _ensure_fd_no_transport(self, fd): + try: + transport = self._transports[fd] + except KeyError: + pass + else: + raise RuntimeError( + 'File descriptor {!r} is used by transport {!r}'.format( + fd, transport)) + + def add_reader(self, fd, callback, *args): + """Add a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._add_reader(fd, callback, *args) + + def remove_reader(self, fd): + """Remove a reader callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_reader(fd) + + def add_writer(self, fd, callback, *args): + """Add a writer callback..""" + self._ensure_fd_no_transport(fd) + return self._add_writer(fd, callback, *args) + + def remove_writer(self, fd): + """Remove a writer callback.""" + self._ensure_fd_no_transport(fd) + return self._remove_writer(fd) + def reset_counters(self): self.remove_reader_count = collections.defaultdict(int) self.remove_writer_count = collections.defaultdict(int) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -321,7 +321,7 @@ self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._fileno, self._read_ready) if waiter is not None: # only wake up the waiter when connection_made() has been called @@ -364,15 +364,15 @@ if self._loop.get_debug(): logger.info("%r was closed by peer", self) self._closing = True - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._protocol.eof_received) self._loop.call_soon(self._call_connection_lost, None) def pause_reading(self): - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) def resume_reading(self): - self._loop.add_reader(self._fileno, self._read_ready) + self._loop._add_reader(self._fileno, self._read_ready) def set_protocol(self, protocol): self._protocol = protocol @@ -412,7 +412,7 @@ def _close(self, exc): self._closing = True - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): @@ -457,7 +457,7 @@ # works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.) if is_socket or (is_fifo and not sys.platform.startswith("aix")): # only start reading when connection_made() has been called - self._loop.call_soon(self._loop.add_reader, + self._loop.call_soon(self._loop._add_reader, self._fileno, self._read_ready) if waiter is not None: @@ -530,7 +530,7 @@ return elif n > 0: data = memoryview(data)[n:] - self._loop.add_writer(self._fileno, self._write_ready) + self._loop._add_writer(self._fileno, self._write_ready) self._buffer += data self._maybe_pause_protocol() @@ -547,15 +547,15 @@ self._conn_lost += 1 # Remove writer here, _fatal_error() doesn't it # because _buffer is empty. - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._fatal_error(exc, 'Fatal write error on pipe transport') else: if n == len(self._buffer): self._buffer.clear() - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._maybe_resume_protocol() # May append to buffer. if self._closing: - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._call_connection_lost(None) return elif n > 0: @@ -570,7 +570,7 @@ assert self._pipe self._closing = True if not self._buffer: - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, None) def set_protocol(self, protocol): @@ -616,9 +616,9 @@ def _close(self, exc=None): self._closing = True if self._buffer: - self._loop.remove_writer(self._fileno) + self._loop._remove_writer(self._fileno) self._buffer.clear() - self._loop.remove_reader(self._fileno) + self._loop._remove_reader(self._fileno) self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -1148,10 +1148,10 @@ m_socket.getaddrinfo = socket.getaddrinfo sock = m_socket.socket.return_value - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.add_writer._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._add_writer._is_coroutine = False coro = self.loop.create_connection(asyncio.Protocol, '1.2.3.4', 80) t, p = self.loop.run_until_complete(coro) @@ -1194,10 +1194,10 @@ m_socket.getaddrinfo = socket.getaddrinfo sock = m_socket.socket.return_value - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.add_writer._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._add_writer._is_coroutine = False for service, port in ('http', 80), (b'http', 80): coro = self.loop.create_connection(asyncio.Protocol, @@ -1614,8 +1614,8 @@ m_socket.getaddrinfo = getaddrinfo m_socket.socket.return_value.bind = bind = mock.Mock() - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False reuseport_supported = hasattr(socket, 'SO_REUSEPORT') coro = self.loop.create_datagram_endpoint( @@ -1646,13 +1646,13 @@ sock = mock.Mock() sock.fileno.return_value = 10 sock.accept.side_effect = OSError(errno.EMFILE, 'Too many open files') - self.loop.remove_reader = mock.Mock() + self.loop._remove_reader = mock.Mock() self.loop.call_later = mock.Mock() self.loop._accept_connection(MyProto, sock) self.assertTrue(m_log.error.called) self.assertFalse(sock.close.called) - self.loop.remove_reader.assert_called_with(10) + self.loop._remove_reader.assert_called_with(10) self.loop.call_later.assert_called_with(constants.ACCEPT_RETRY_DELAY, # self.loop._start_serving mock.ANY, diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -72,11 +72,11 @@ @unittest.skipIf(ssl is None, 'No ssl module') def test_make_ssl_transport(self): m = mock.Mock() - self.loop.add_reader = mock.Mock() - self.loop.add_reader._is_coroutine = False - self.loop.add_writer = mock.Mock() - self.loop.remove_reader = mock.Mock() - self.loop.remove_writer = mock.Mock() + self.loop._add_reader = mock.Mock() + self.loop._add_reader._is_coroutine = False + self.loop._add_writer = mock.Mock() + self.loop._remove_reader = mock.Mock() + self.loop._remove_writer = mock.Mock() waiter = asyncio.Future(loop=self.loop) with test_utils.disable_logger(): transport = self.loop._make_ssl_transport( @@ -119,7 +119,7 @@ ssock.fileno.return_value = 7 csock = self.loop._csock csock.fileno.return_value = 1 - remove_reader = self.loop.remove_reader = mock.Mock() + remove_reader = self.loop._remove_reader = mock.Mock() self.loop._selector.close() self.loop._selector = selector = mock.Mock() @@ -651,12 +651,12 @@ reader = mock.Mock() reader.cancelled = True - self.loop.remove_reader = mock.Mock() + self.loop._remove_reader = mock.Mock() self.loop._process_events( [(selectors.SelectorKey( 1, 1, selectors.EVENT_READ, (reader, None)), selectors.EVENT_READ)]) - self.loop.remove_reader.assert_called_with(1) + self.loop._remove_reader.assert_called_with(1) def test_process_events_write(self): writer = mock.Mock() @@ -672,13 +672,13 @@ def test_process_events_write_cancelled(self): writer = mock.Mock() writer.cancelled = True - self.loop.remove_writer = mock.Mock() + self.loop._remove_writer = mock.Mock() self.loop._process_events( [(selectors.SelectorKey(1, 1, selectors.EVENT_WRITE, (None, writer)), selectors.EVENT_WRITE)]) - self.loop.remove_writer.assert_called_with(1) + self.loop._remove_writer.assert_called_with(1) def test_accept_connection_multiple(self): sock = mock.Mock() @@ -747,8 +747,8 @@ def test_force_close(self): tr = self.create_transport() tr._buffer.extend(b'1') - self.loop.add_reader(7, mock.sentinel) - self.loop.add_writer(7, mock.sentinel) + self.loop._add_reader(7, mock.sentinel) + self.loop._add_writer(7, mock.sentinel) tr._force_close(None) self.assertTrue(tr.is_closing()) @@ -1037,7 +1037,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.assertTrue(self.sock.send.called) self.assertFalse(self.loop.writers) @@ -1049,7 +1049,7 @@ transport = self.socket_transport() transport._closing = True transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.assertTrue(self.sock.send.called) self.assertFalse(self.loop.writers) @@ -1067,7 +1067,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) self.assertEqual(list_to_buffer([b'ta']), transport._buffer) @@ -1078,7 +1078,7 @@ transport = self.socket_transport() transport._buffer.extend(data) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) self.assertEqual(list_to_buffer([b'data']), transport._buffer) @@ -1088,7 +1088,7 @@ transport = self.socket_transport() transport._buffer = list_to_buffer([b'data1', b'data2']) - self.loop.add_writer(7, transport._write_ready) + self.loop._add_writer(7, transport._write_ready) transport._write_ready() self.loop.assert_writer(7, transport._write_ready) @@ -1130,7 +1130,7 @@ @mock.patch('asyncio.base_events.logger') def test_transport_close_remove_writer(self, m_log): - remove_writer = self.loop.remove_writer = mock.Mock() + remove_writer = self.loop._remove_writer = mock.Mock() transport = self.socket_transport() transport.close() @@ -1288,7 +1288,7 @@ self.assertEqual((b'data',), self.protocol.data_received.call_args[0]) def test_read_ready_write_wants_read(self): - self.loop.add_writer = mock.Mock() + self.loop._add_writer = mock.Mock() self.sslsock.recv.side_effect = BlockingIOError transport = self._make_one() transport._write_wants_read = True @@ -1298,7 +1298,7 @@ self.assertFalse(transport._write_wants_read) transport._write_ready.assert_called_with() - self.loop.add_writer.assert_called_with( + self.loop._add_writer.assert_called_with( transport._sock_fd, transport._write_ready) def test_read_ready_recv_eof(self): @@ -1333,16 +1333,16 @@ self.assertFalse(self.protocol.data_received.called) def test_read_ready_recv_write(self): - self.loop.remove_reader = mock.Mock() - self.loop.add_writer = mock.Mock() + self.loop._remove_reader = mock.Mock() + self.loop._add_writer = mock.Mock() self.sslsock.recv.side_effect = ssl.SSLWantWriteError transport = self._make_one() transport._read_ready() self.assertFalse(self.protocol.data_received.called) self.assertTrue(transport._read_wants_write) - self.loop.remove_reader.assert_called_with(transport._sock_fd) - self.loop.add_writer.assert_called_with( + self.loop._remove_reader.assert_called_with(transport._sock_fd) + self.loop._add_writer.assert_called_with( transport._sock_fd, transport._write_ready) def test_read_ready_recv_exc(self): @@ -1419,12 +1419,12 @@ transport = self._make_one() transport._buffer = list_to_buffer([b'data']) - self.loop.remove_writer = mock.Mock() + self.loop._remove_writer = mock.Mock() self.sslsock.send.side_effect = ssl.SSLWantReadError transport._write_ready() self.assertFalse(self.protocol.data_received.called) self.assertTrue(transport._write_wants_read) - self.loop.remove_writer.assert_called_with(transport._sock_fd) + self.loop._remove_writer.assert_called_with(transport._sock_fd) def test_write_ready_send_exc(self): err = self.sslsock.send.side_effect = OSError() @@ -1439,7 +1439,7 @@ self.assertEqual(list_to_buffer(), transport._buffer) def test_write_ready_read_wants_write(self): - self.loop.add_reader = mock.Mock() + self.loop._add_reader = mock.Mock() self.sslsock.send.side_effect = BlockingIOError transport = self._make_one() transport._read_wants_write = True @@ -1448,7 +1448,7 @@ self.assertFalse(transport._read_wants_write) transport._read_ready.assert_called_with() - self.loop.add_reader.assert_called_with( + self.loop._add_reader.assert_called_with( transport._sock_fd, transport._read_ready) def test_write_eof(self): @@ -1699,7 +1699,7 @@ transport = self.datagram_transport() transport._buffer.append((data, ('0.0.0.0', 12345))) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.assertTrue(self.sock.sendto.called) self.assertEqual( @@ -1713,7 +1713,7 @@ transport = self.datagram_transport() transport._closing = True transport._buffer.append((data, ())) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.sock.sendto.assert_called_with(data, ()) self.assertFalse(self.loop.writers) @@ -1722,7 +1722,7 @@ def test_sendto_ready_no_data(self): transport = self.datagram_transport() - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.assertFalse(self.sock.sendto.called) self.assertFalse(self.loop.writers) @@ -1732,7 +1732,7 @@ transport = self.datagram_transport() transport._buffer.extend([(b'data1', ()), (b'data2', ())]) - self.loop.add_writer(7, transport._sendto_ready) + self.loop._add_writer(7, transport._sendto_ready) transport._sendto_ready() self.loop.assert_writer(7, transport._sendto_ready) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -350,6 +350,9 @@ no loop attached. Patch by Vincent Michel. +- Issue #28369: Raise RuntimeError when transport's FD is used with + add_reader, add_writer, etc. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 18:04:56 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 22:04:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2328370=29?= Message-ID: <20161005220453.5035.15329.C8438D05@psf.io> https://hg.python.org/cpython/rev/b76553de3a29 changeset: 104306:b76553de3a29 branch: 3.6 parent: 104303:f3c1d8869dd5 parent: 104305:b3ef922e6f26 user: Yury Selivanov date: Wed Oct 05 18:04:35 2016 -0400 summary: Merge 3.5 (issue #28370) files: Lib/asyncio/streams.py | 32 ++++++++++++++--------------- Misc/NEWS | 3 ++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -448,6 +448,7 @@ assert not self._eof, '_wait_for_data after EOF' # Waiting for data while paused will make deadlock, so prevent it. + # This is essential for readexactly(n) for case when n > self._limit. if self._paused: self._paused = False self._transport.resume_reading() @@ -658,25 +659,22 @@ if n == 0: return b'' - # There used to be "optimized" code here. It created its own - # Future and waited until self._buffer had at least the n - # bytes, then called read(n). Unfortunately, this could pause - # the transport if the argument was larger than the pause - # limit (which is twice self._limit). So now we just read() - # into a local buffer. + while len(self._buffer) < n: + if self._eof: + incomplete = bytes(self._buffer) + self._buffer.clear() + raise IncompleteReadError(incomplete, n) - blocks = [] - while n > 0: - block = yield from self.read(n) - if not block: - partial = b''.join(blocks) - raise IncompleteReadError(partial, len(partial) + n) - blocks.append(block) - n -= len(block) + yield from self._wait_for_data('readexactly') - assert n == 0 - - return b''.join(blocks) + if len(self._buffer) == n: + data = bytes(self._buffer) + self._buffer.clear() + else: + data = bytes(self._buffer[:n]) + del self._buffer[:n] + self._maybe_resume_transport() + return data if compat.PY35: @coroutine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -170,6 +170,9 @@ - Issue #28369: Raise RuntimeError when transport's FD is used with add_reader, add_writer, etc. +- Issue #28370: Speedup asyncio.StreamReader.readexactly. + Patch by ????????? ????. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 18:17:24 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 22:17:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzcw?= =?utf-8?q?=3A_Speedup_asyncio=2EStreamReader=2Ereadexactly?= Message-ID: <20161005220453.17441.85463.9DA07AA2@psf.io> https://hg.python.org/cpython/rev/b3ef922e6f26 changeset: 104305:b3ef922e6f26 branch: 3.5 parent: 104302:2b502f624753 user: Yury Selivanov date: Wed Oct 05 18:01:12 2016 -0400 summary: Issue #28370: Speedup asyncio.StreamReader.readexactly Patch by ????????? ????. files: Lib/asyncio/streams.py | 32 ++++++++++++++--------------- Misc/NEWS | 3 ++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -448,6 +448,7 @@ assert not self._eof, '_wait_for_data after EOF' # Waiting for data while paused will make deadlock, so prevent it. + # This is essential for readexactly(n) for case when n > self._limit. if self._paused: self._paused = False self._transport.resume_reading() @@ -658,25 +659,22 @@ if n == 0: return b'' - # There used to be "optimized" code here. It created its own - # Future and waited until self._buffer had at least the n - # bytes, then called read(n). Unfortunately, this could pause - # the transport if the argument was larger than the pause - # limit (which is twice self._limit). So now we just read() - # into a local buffer. + while len(self._buffer) < n: + if self._eof: + incomplete = bytes(self._buffer) + self._buffer.clear() + raise IncompleteReadError(incomplete, n) - blocks = [] - while n > 0: - block = yield from self.read(n) - if not block: - partial = b''.join(blocks) - raise IncompleteReadError(partial, len(partial) + n) - blocks.append(block) - n -= len(block) + yield from self._wait_for_data('readexactly') - assert n == 0 - - return b''.join(blocks) + if len(self._buffer) == n: + data = bytes(self._buffer) + self._buffer.clear() + else: + data = bytes(self._buffer[:n]) + del self._buffer[:n] + self._maybe_resume_transport() + return data if compat.PY35: @coroutine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -353,6 +353,9 @@ - Issue #28369: Raise RuntimeError when transport's FD is used with add_reader, add_writer, etc. +- Issue #28370: Speedup asyncio.StreamReader.readexactly. + Patch by ????????? ????. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 18:17:38 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 22:17:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjgzNzAp?= Message-ID: <20161005220453.15320.65720.BF258C6F@psf.io> https://hg.python.org/cpython/rev/5913c2b1d80a changeset: 104307:5913c2b1d80a parent: 104304:745e0ff513c2 parent: 104306:b76553de3a29 user: Yury Selivanov date: Wed Oct 05 18:04:48 2016 -0400 summary: Merge 3.6 (issue #28370) files: Lib/asyncio/streams.py | 32 ++++++++++++++--------------- Misc/NEWS | 3 ++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -448,6 +448,7 @@ assert not self._eof, '_wait_for_data after EOF' # Waiting for data while paused will make deadlock, so prevent it. + # This is essential for readexactly(n) for case when n > self._limit. if self._paused: self._paused = False self._transport.resume_reading() @@ -658,25 +659,22 @@ if n == 0: return b'' - # There used to be "optimized" code here. It created its own - # Future and waited until self._buffer had at least the n - # bytes, then called read(n). Unfortunately, this could pause - # the transport if the argument was larger than the pause - # limit (which is twice self._limit). So now we just read() - # into a local buffer. + while len(self._buffer) < n: + if self._eof: + incomplete = bytes(self._buffer) + self._buffer.clear() + raise IncompleteReadError(incomplete, n) - blocks = [] - while n > 0: - block = yield from self.read(n) - if not block: - partial = b''.join(blocks) - raise IncompleteReadError(partial, len(partial) + n) - blocks.append(block) - n -= len(block) + yield from self._wait_for_data('readexactly') - assert n == 0 - - return b''.join(blocks) + if len(self._buffer) == n: + data = bytes(self._buffer) + self._buffer.clear() + else: + data = bytes(self._buffer[:n]) + del self._buffer[:n] + self._maybe_resume_transport() + return data if compat.PY35: @coroutine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -181,6 +181,9 @@ - Issue #28369: Raise RuntimeError when transport's FD is used with add_reader, add_writer, etc. +- Issue #28370: Speedup asyncio.StreamReader.readexactly. + Patch by ????????? ????. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 18:29:38 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 22:29:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2328371=29?= Message-ID: <20161005222938.20829.95220.C6086001@psf.io> https://hg.python.org/cpython/rev/c0d84c091db0 changeset: 104309:c0d84c091db0 branch: 3.6 parent: 104306:b76553de3a29 parent: 104308:c8e71ddf1db5 user: Yury Selivanov date: Wed Oct 05 18:29:04 2016 -0400 summary: Merge 3.5 (issue #28371) files: Lib/asyncio/base_events.py | 3 +++ Lib/test/test_asyncio/test_base_events.py | 9 ++++++--- Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -606,6 +606,9 @@ if isinstance(func, events.Handle): assert not args assert not isinstance(func, events.TimerHandle) + warnings.warn( + "Passing Handle to loop.run_in_executor() is deprecated", + DeprecationWarning) if func._cancelled: f = self.create_future() f.set_result(None) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -358,7 +358,8 @@ h = asyncio.Handle(cb, (), self.loop) h.cancel() - f = self.loop.run_in_executor(None, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + f = self.loop.run_in_executor(None, h) self.assertIsInstance(f, asyncio.Future) self.assertTrue(f.done()) self.assertIsNone(f.result()) @@ -373,12 +374,14 @@ self.loop.set_default_executor(executor) - res = self.loop.run_in_executor(None, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + res = self.loop.run_in_executor(None, h) self.assertIs(f, res) executor = mock.Mock() executor.submit.return_value = f - res = self.loop.run_in_executor(executor, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + res = self.loop.run_in_executor(executor, h) self.assertIs(f, res) self.assertTrue(executor.submit.called) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -173,6 +173,8 @@ - Issue #28370: Speedup asyncio.StreamReader.readexactly. Patch by ????????? ????. +- Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 18:29:38 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 22:29:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzcx?= =?utf-8?q?=3A_Deprecate_passing_asyncio=2EHandles_to_run=5Fin=5Fexecutor?= =?utf-8?q?=2E?= Message-ID: <20161005222938.20698.74225.EEC1B682@psf.io> https://hg.python.org/cpython/rev/c8e71ddf1db5 changeset: 104308:c8e71ddf1db5 branch: 3.5 parent: 104305:b3ef922e6f26 user: Yury Selivanov date: Wed Oct 05 18:28:09 2016 -0400 summary: Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. files: Lib/asyncio/base_events.py | 3 +++ Lib/test/test_asyncio/test_base_events.py | 9 ++++++--- Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -605,6 +605,9 @@ if isinstance(func, events.Handle): assert not args assert not isinstance(func, events.TimerHandle) + warnings.warn( + "Passing Handle to loop.run_in_executor() is deprecated", + DeprecationWarning) if func._cancelled: f = self.create_future() f.set_result(None) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -358,7 +358,8 @@ h = asyncio.Handle(cb, (), self.loop) h.cancel() - f = self.loop.run_in_executor(None, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + f = self.loop.run_in_executor(None, h) self.assertIsInstance(f, asyncio.Future) self.assertTrue(f.done()) self.assertIsNone(f.result()) @@ -373,12 +374,14 @@ self.loop.set_default_executor(executor) - res = self.loop.run_in_executor(None, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + res = self.loop.run_in_executor(None, h) self.assertIs(f, res) executor = mock.Mock() executor.submit.return_value = f - res = self.loop.run_in_executor(executor, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + res = self.loop.run_in_executor(executor, h) self.assertIs(f, res) self.assertTrue(executor.submit.called) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -356,6 +356,8 @@ - Issue #28370: Speedup asyncio.StreamReader.readexactly. Patch by ????????? ????. +- Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 18:29:39 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 22:29:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjgzNzEp?= Message-ID: <20161005222939.95017.6004.2BB575F8@psf.io> https://hg.python.org/cpython/rev/893f65369fea changeset: 104310:893f65369fea parent: 104307:5913c2b1d80a parent: 104309:c0d84c091db0 user: Yury Selivanov date: Wed Oct 05 18:29:33 2016 -0400 summary: Merge 3.6 (issue #28371) files: Lib/asyncio/base_events.py | 3 +++ Lib/test/test_asyncio/test_base_events.py | 9 ++++++--- Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -606,6 +606,9 @@ if isinstance(func, events.Handle): assert not args assert not isinstance(func, events.TimerHandle) + warnings.warn( + "Passing Handle to loop.run_in_executor() is deprecated", + DeprecationWarning) if func._cancelled: f = self.create_future() f.set_result(None) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -358,7 +358,8 @@ h = asyncio.Handle(cb, (), self.loop) h.cancel() - f = self.loop.run_in_executor(None, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + f = self.loop.run_in_executor(None, h) self.assertIsInstance(f, asyncio.Future) self.assertTrue(f.done()) self.assertIsNone(f.result()) @@ -373,12 +374,14 @@ self.loop.set_default_executor(executor) - res = self.loop.run_in_executor(None, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + res = self.loop.run_in_executor(None, h) self.assertIs(f, res) executor = mock.Mock() executor.submit.return_value = f - res = self.loop.run_in_executor(executor, h) + with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"): + res = self.loop.run_in_executor(executor, h) self.assertIs(f, res) self.assertTrue(executor.submit.called) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -184,6 +184,8 @@ - Issue #28370: Speedup asyncio.StreamReader.readexactly. Patch by ????????? ????. +- Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 19:33:57 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 23:33:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzcy?= =?utf-8?q?=3A_Fix_asyncio_to_support_formatting_of_non-python_coroutines?= Message-ID: <20161005233357.17369.37001.0FE2963D@psf.io> https://hg.python.org/cpython/rev/7bacd209ac4f changeset: 104311:7bacd209ac4f branch: 3.5 parent: 104308:c8e71ddf1db5 user: Yury Selivanov date: Wed Oct 05 19:32:49 2016 -0400 summary: Issue #28372: Fix asyncio to support formatting of non-python coroutines files: Lib/asyncio/coroutines.py | 19 ++++++++ Lib/test/test_asyncio/test_events.py | 34 ++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 55 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -261,6 +261,25 @@ def _format_coroutine(coro): assert iscoroutine(coro) + if not hasattr(coro, 'cr_code') and not hasattr(coro, 'gi_code'): + # Most likely a Cython coroutine. + coro_name = getattr(coro, '__qualname__', coro.__name__) + coro_name = '{}()'.format(coro_name) + + running = False + try: + running = coro.cr_running + except AttributeError: + try: + running = coro.gi_running + except AttributeError: + pass + + if running: + return '{} running'.format(coro_name) + else: + return coro_name + coro_name = None if isinstance(coro, CoroWrapper): func = coro.func diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1,5 +1,6 @@ """Tests for events.py.""" +import collections.abc import functools import gc import io @@ -25,6 +26,7 @@ import tty import asyncio +from asyncio import coroutines from asyncio import proactor_events from asyncio import selector_events from asyncio import sslproto @@ -2380,6 +2382,38 @@ h = loop.call_later(0, noop) check_source_traceback(h) + @unittest.skipUnless(hasattr(collections.abc, 'Coroutine'), + 'No collections.abc.Coroutine') + def test_coroutine_like_object_debug_formatting(self): + # Test that asyncio can format coroutines that are instances of + # collections.abc.Coroutine, but lack cr_core or gi_code attributes + # (such as ones compiled with Cython). + + class Coro: + __name__ = 'AAA' + + def send(self, v): + pass + + def throw(self, *exc): + pass + + def close(self): + pass + + def __await__(self): + pass + + coro = Coro() + self.assertTrue(asyncio.iscoroutine(coro)) + self.assertEqual(coroutines._format_coroutine(coro), 'AAA()') + + coro.__qualname__ = 'BBB' + self.assertEqual(coroutines._format_coroutine(coro), 'BBB()') + + coro.cr_running = True + self.assertEqual(coroutines._format_coroutine(coro), 'BBB() running') + class TimerTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -358,6 +358,8 @@ - Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. +- Issue #28372: Fix asyncio to support formatting of non-python coroutines. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 19:33:58 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 23:33:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjgzNzIp?= Message-ID: <20161005233357.95121.80951.E6BDAB16@psf.io> https://hg.python.org/cpython/rev/8bc3e9754b3d changeset: 104313:8bc3e9754b3d parent: 104310:893f65369fea parent: 104312:f7550d535878 user: Yury Selivanov date: Wed Oct 05 19:33:52 2016 -0400 summary: Merge 3.6 (issue #28372) files: Lib/asyncio/coroutines.py | 19 ++++++++ Lib/test/test_asyncio/test_events.py | 34 ++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 55 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -261,6 +261,25 @@ def _format_coroutine(coro): assert iscoroutine(coro) + if not hasattr(coro, 'cr_code') and not hasattr(coro, 'gi_code'): + # Most likely a Cython coroutine. + coro_name = getattr(coro, '__qualname__', coro.__name__) + coro_name = '{}()'.format(coro_name) + + running = False + try: + running = coro.cr_running + except AttributeError: + try: + running = coro.gi_running + except AttributeError: + pass + + if running: + return '{} running'.format(coro_name) + else: + return coro_name + coro_name = None if isinstance(coro, CoroWrapper): func = coro.func diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1,5 +1,6 @@ """Tests for events.py.""" +import collections.abc import functools import gc import io @@ -25,6 +26,7 @@ import tty import asyncio +from asyncio import coroutines from asyncio import proactor_events from asyncio import selector_events from asyncio import sslproto @@ -2380,6 +2382,38 @@ h = loop.call_later(0, noop) check_source_traceback(h) + @unittest.skipUnless(hasattr(collections.abc, 'Coroutine'), + 'No collections.abc.Coroutine') + def test_coroutine_like_object_debug_formatting(self): + # Test that asyncio can format coroutines that are instances of + # collections.abc.Coroutine, but lack cr_core or gi_code attributes + # (such as ones compiled with Cython). + + class Coro: + __name__ = 'AAA' + + def send(self, v): + pass + + def throw(self, *exc): + pass + + def close(self): + pass + + def __await__(self): + pass + + coro = Coro() + self.assertTrue(asyncio.iscoroutine(coro)) + self.assertEqual(coroutines._format_coroutine(coro), 'AAA()') + + coro.__qualname__ = 'BBB' + self.assertEqual(coroutines._format_coroutine(coro), 'BBB()') + + coro.cr_running = True + self.assertEqual(coroutines._format_coroutine(coro), 'BBB() running') + class TimerTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -186,6 +186,8 @@ - Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. +- Issue #28372: Fix asyncio to support formatting of non-python coroutines. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 19:33:57 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 23:33:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2328372=29?= Message-ID: <20161005233357.21292.90729.5D9FDCDF@psf.io> https://hg.python.org/cpython/rev/f7550d535878 changeset: 104312:f7550d535878 branch: 3.6 parent: 104309:c0d84c091db0 parent: 104311:7bacd209ac4f user: Yury Selivanov date: Wed Oct 05 19:33:36 2016 -0400 summary: Merge 3.5 (issue #28372) files: Lib/asyncio/coroutines.py | 19 ++++++++ Lib/test/test_asyncio/test_events.py | 34 ++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 55 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -261,6 +261,25 @@ def _format_coroutine(coro): assert iscoroutine(coro) + if not hasattr(coro, 'cr_code') and not hasattr(coro, 'gi_code'): + # Most likely a Cython coroutine. + coro_name = getattr(coro, '__qualname__', coro.__name__) + coro_name = '{}()'.format(coro_name) + + running = False + try: + running = coro.cr_running + except AttributeError: + try: + running = coro.gi_running + except AttributeError: + pass + + if running: + return '{} running'.format(coro_name) + else: + return coro_name + coro_name = None if isinstance(coro, CoroWrapper): func = coro.func diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1,5 +1,6 @@ """Tests for events.py.""" +import collections.abc import functools import gc import io @@ -25,6 +26,7 @@ import tty import asyncio +from asyncio import coroutines from asyncio import proactor_events from asyncio import selector_events from asyncio import sslproto @@ -2380,6 +2382,38 @@ h = loop.call_later(0, noop) check_source_traceback(h) + @unittest.skipUnless(hasattr(collections.abc, 'Coroutine'), + 'No collections.abc.Coroutine') + def test_coroutine_like_object_debug_formatting(self): + # Test that asyncio can format coroutines that are instances of + # collections.abc.Coroutine, but lack cr_core or gi_code attributes + # (such as ones compiled with Cython). + + class Coro: + __name__ = 'AAA' + + def send(self, v): + pass + + def throw(self, *exc): + pass + + def close(self): + pass + + def __await__(self): + pass + + coro = Coro() + self.assertTrue(asyncio.iscoroutine(coro)) + self.assertEqual(coroutines._format_coroutine(coro), 'AAA()') + + coro.__qualname__ = 'BBB' + self.assertEqual(coroutines._format_coroutine(coro), 'BBB()') + + coro.cr_running = True + self.assertEqual(coroutines._format_coroutine(coro), 'BBB() running') + class TimerTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -175,6 +175,8 @@ - Issue #28371: Deprecate passing asyncio.Handles to run_in_executor. +- Issue #28372: Fix asyncio to support formatting of non-python coroutines. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 19:40:44 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 23:40:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2323749=29?= Message-ID: <20161005234044.20094.72210.FF40F490@psf.io> https://hg.python.org/cpython/rev/3e6739e5c2d0 changeset: 104315:3e6739e5c2d0 branch: 3.6 parent: 104312:f7550d535878 parent: 104314:3771a6326725 user: Yury Selivanov date: Wed Oct 05 19:40:19 2016 -0400 summary: Merge 3.5 (issue #23749) files: Lib/asyncio/sslproto.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -411,7 +411,8 @@ """ def __init__(self, loop, app_protocol, sslcontext, waiter, - server_side=False, server_hostname=None): + server_side=False, server_hostname=None, + call_connection_made=True): if ssl is None: raise RuntimeError('stdlib ssl module not available') @@ -444,6 +445,7 @@ self._in_shutdown = False # transport, ex: SelectorSocketTransport self._transport = None + self._call_connection_made = call_connection_made def _wakeup_waiter(self, exc=None): if self._waiter is None: @@ -607,7 +609,8 @@ compression=sslobj.compression(), ssl_object=sslobj, ) - self._app_protocol.connection_made(self._app_transport) + if self._call_connection_made: + self._app_protocol.connection_made(self._app_transport) self._wakeup_waiter() self._session_established = True # In case transport.write() was already called. Don't call -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 19:40:44 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 23:40:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogYXN5bmNpbzogQWRk?= =?utf-8?q?_=22call=5Fconnection=5Fmade=22_arg_to_SSLProtocol=2E=5F=5Finit?= =?utf-8?b?X18=?= Message-ID: <20161005234044.75980.6868.BA28AB33@psf.io> https://hg.python.org/cpython/rev/3771a6326725 changeset: 104314:3771a6326725 branch: 3.5 parent: 104311:7bacd209ac4f user: Yury Selivanov date: Wed Oct 05 19:39:54 2016 -0400 summary: asyncio: Add "call_connection_made" arg to SSLProtocol.__init__ Issue #23749: With this change it's possible to implement starttls as a separate package on PyPI, or even by copying/pasting a small snipped of code in your project. It's expected that we'll figure out the API design for starttls during 3.6, so that we can add it in 3.7. files: Lib/asyncio/sslproto.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -410,7 +410,8 @@ """ def __init__(self, loop, app_protocol, sslcontext, waiter, - server_side=False, server_hostname=None): + server_side=False, server_hostname=None, + call_connection_made=True): if ssl is None: raise RuntimeError('stdlib ssl module not available') @@ -443,6 +444,7 @@ self._in_shutdown = False # transport, ex: SelectorSocketTransport self._transport = None + self._call_connection_made = call_connection_made def _wakeup_waiter(self, exc=None): if self._waiter is None: @@ -606,7 +608,8 @@ compression=sslobj.compression(), ssl_object=sslobj, ) - self._app_protocol.connection_made(self._app_transport) + if self._call_connection_made: + self._app_protocol.connection_made(self._app_transport) self._wakeup_waiter() self._session_established = True # In case transport.write() was already called. Don't call -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 5 19:40:44 2016 From: python-checkins at python.org (yury.selivanov) Date: Wed, 05 Oct 2016 23:40:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjM3NDkp?= Message-ID: <20161005234044.85988.21066.6E29C857@psf.io> https://hg.python.org/cpython/rev/f2204eaba685 changeset: 104316:f2204eaba685 parent: 104313:8bc3e9754b3d parent: 104315:3e6739e5c2d0 user: Yury Selivanov date: Wed Oct 05 19:40:40 2016 -0400 summary: Merge 3.6 (issue #23749) files: Lib/asyncio/sslproto.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -411,7 +411,8 @@ """ def __init__(self, loop, app_protocol, sslcontext, waiter, - server_side=False, server_hostname=None): + server_side=False, server_hostname=None, + call_connection_made=True): if ssl is None: raise RuntimeError('stdlib ssl module not available') @@ -444,6 +445,7 @@ self._in_shutdown = False # transport, ex: SelectorSocketTransport self._transport = None + self._call_connection_made = call_connection_made def _wakeup_waiter(self, exc=None): if self._waiter is None: @@ -607,7 +609,8 @@ compression=sslobj.compression(), ssl_object=sslobj, ) - self._app_protocol.connection_made(self._app_transport) + if self._call_connection_made: + self._app_protocol.connection_made(self._app_transport) self._wakeup_waiter() self._session_established = True # In case transport.write() was already called. Don't call -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 00:45:57 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 04:45:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogbW1hcDogZG8gYWxs?= =?utf-8?q?_internal_arithmetic_with_Py=5Fssize=5Ft_while_being_very_caref?= =?utf-8?q?ul_about?= Message-ID: <20161006044557.85616.68553.F9F920D7@psf.io> https://hg.python.org/cpython/rev/144f10202076 changeset: 104317:144f10202076 branch: 2.7 parent: 104275:522adc2e082a user: Benjamin Peterson date: Wed Oct 05 21:45:48 2016 -0700 summary: mmap: do all internal arithmetic with Py_ssize_t while being very careful about overflow files: Lib/test/test_mmap.py | 10 + Misc/NEWS | 3 + Modules/mmapmodule.c | 184 ++++++++++++----------------- 3 files changed, 91 insertions(+), 106 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -652,6 +652,16 @@ finally: s.close() + def test_resize_past_pos(self): + m = mmap.mmap(-1, 8192) + self.addCleanup(m.close) + m.read(5000) + m.resize(4096) + self.assertEqual(m.read(14), '') + self.assertRaises(ValueError, m.read_byte,) + self.assertRaises(ValueError, m.write_byte, 'b') + self.assertRaises(ValueError, m.write, 'abc') + class LargeMmapTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,9 @@ Library ------- +- Fix possible integer overflows and crashes in the mmap module with unusual + usage patterns. + - Issue #27897: Fixed possible crash in sqlite3.Connection.create_collation() if pass invalid string-like object as a name. Original patch by Xiang Zhang. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -91,8 +91,8 @@ typedef struct { PyObject_HEAD char * data; - size_t size; - size_t pos; /* relative to offset */ + Py_ssize_t size; + Py_ssize_t pos; /* relative to offset */ #ifdef MS_WINDOWS PY_LONG_LONG offset; #else @@ -204,33 +204,32 @@ PyObject *unused) { CHECK_VALID(NULL); - if (self->pos < self->size) { - char value = self->data[self->pos]; - self->pos += 1; - return Py_BuildValue("c", value); - } else { + if (self->pos >= self->size) { PyErr_SetString(PyExc_ValueError, "read byte out of range"); return NULL; } + return PyString_FromStringAndSize(&self->data[self->pos++], 1); } static PyObject * mmap_read_line_method(mmap_object *self, PyObject *unused) { - char *start = self->data+self->pos; - char *eof = self->data+self->size; - char *eol; + Py_ssize_t remaining; + char *start, *eol; PyObject *result; CHECK_VALID(NULL); - eol = memchr(start, '\n', self->size - self->pos); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (!remaining) + return PyString_FromString(""); + start = self->data + self->pos; + eol = memchr(start, '\n', remaining); if (!eol) - eol = eof; + eol = self->data + self->size; else - ++eol; /* we're interested in the position after the - newline. */ + ++eol; /* advance past newline */ result = PyString_FromStringAndSize(start, (eol - start)); self->pos += (eol - start); return result; @@ -240,28 +239,18 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes, n; + Py_ssize_t num_bytes, remaining; PyObject *result; CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "n:read", &num_bytes)) - return(NULL); + return NULL; /* silently 'adjust' out-of-range requests */ - assert(self->size >= self->pos); - n = self->size - self->pos; - /* The difference can overflow, only if self->size is greater than - * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed, - * because the mapped area and the returned string each need more - * than half of the addressable memory. So we clip the size, and let - * the code below raise MemoryError. - */ - if (n < 0) - n = PY_SSIZE_T_MAX; - if (num_bytes < 0 || num_bytes > n) { - num_bytes = n; - } - result = Py_BuildValue("s#", self->data+self->pos, num_bytes); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (num_bytes < 0 || num_bytes > remaining) + num_bytes = remaining; + result = PyString_FromStringAndSize(&self->data[self->pos], num_bytes); self->pos += num_bytes; return result; } @@ -288,14 +277,14 @@ start += self->size; if (start < 0) start = 0; - else if ((size_t)start > self->size) + else if (start > self->size) start = self->size; if (end < 0) end += self->size; if (end < 0) end = 0; - else if ((size_t)end > self->size) + else if (end > self->size) end = self->size; start_p = self->data + start; @@ -362,12 +351,12 @@ if (!is_writeable(self)) return NULL; - if ((self->pos + length) > self->size) { + if (self->pos > self->size || self->size - self->pos < length) { PyErr_SetString(PyExc_ValueError, "data out of range"); return NULL; } - memcpy(self->data+self->pos, data, length); - self->pos = self->pos+length; + memcpy(&self->data[self->pos], data, length); + self->pos += length; Py_INCREF(Py_None); return Py_None; } @@ -386,8 +375,7 @@ return NULL; if (self->pos < self->size) { - *(self->data+self->pos) = value; - self->pos += 1; + self->data[self->pos++] = value; Py_INCREF(Py_None); return Py_None; } @@ -458,8 +446,14 @@ if (!PyArg_ParseTuple(args, "n:resize", &new_size) || !is_resizeable(self)) { return NULL; + } + if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { + PyErr_SetString(PyExc_ValueError, "new size out of range"); + return NULL; + } + + { #ifdef MS_WINDOWS - } else { DWORD dwErrCode = 0; DWORD off_hi, off_lo, newSizeLow, newSizeHigh; /* First, unmap the file view */ @@ -509,15 +503,13 @@ #ifdef UNIX #ifndef HAVE_MREMAP - } else { PyErr_SetString(PyExc_SystemError, "mmap: resizing not available--no mremap()"); return NULL; #else - } else { void *newmap; - if (ftruncate(self->fd, self->offset + new_size) == -1) { + if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { PyErr_SetFromErrno(mmap_module_error); return NULL; } @@ -525,11 +517,11 @@ #ifdef MREMAP_MAYMOVE newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); #else - #if defined(__NetBSD__) - newmap = mremap(self->data, self->size, self->data, new_size, 0); - #else - newmap = mremap(self->data, self->size, new_size, 0); - #endif /* __NetBSD__ */ +#if defined(__NetBSD__) + newmap = mremap(self->data, self->size, self->data, new_size, 0); +#else + newmap = mremap(self->data, self->size, new_size, 0); +#endif /* __NetBSD__ */ #endif if (newmap == (void *)-1) { @@ -560,7 +552,7 @@ CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) return NULL; - if ((size_t)(offset + size) > self->size) { + if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; } @@ -601,12 +593,12 @@ where = dist; break; case 1: /* relative to current position */ - if ((Py_ssize_t)self->pos + dist < 0) + if (PY_SSIZE_T_MAX - self->pos < dist) goto onoutofrange; where = self->pos + dist; break; case 2: /* relative to end */ - if ((Py_ssize_t)self->size + dist < 0) + if (PY_SSIZE_T_MAX - self->size < dist) goto onoutofrange; where = self->size + dist; break; @@ -629,23 +621,27 @@ static PyObject * mmap_move_method(mmap_object *self, PyObject *args) { - unsigned long dest, src, cnt; + Py_ssize_t dest, src, cnt; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) || + if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || !is_writeable(self)) { return NULL; } else { /* bounds check the values */ - if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt || - src < 0 || src > self->size || (src + cnt) > self->size || - dest < 0 || dest > self->size || (dest + cnt) > self->size) { - PyErr_SetString(PyExc_ValueError, - "source, destination, or count out of range"); - return NULL; - } - memmove(self->data+dest, self->data+src, cnt); + if (dest < 0 || src < 0 || cnt < 0) + goto bounds; + if (self->size - dest < cnt || self->size - src < cnt) + goto bounds; + + memmove(&self->data[dest], &self->data[src], cnt); + Py_INCREF(Py_None); return Py_None; + + bounds: + PyErr_SetString(PyExc_ValueError, + "source, destination, or count out of range"); + return NULL; } } @@ -745,7 +741,7 @@ mmap_item(mmap_object *self, Py_ssize_t i) { CHECK_VALID(NULL); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } @@ -758,13 +754,13 @@ CHECK_VALID(NULL); if (ilow < 0) ilow = 0; - else if ((size_t)ilow > self->size) + else if (ilow > self->size) ilow = self->size; if (ihigh < 0) ihigh = 0; if (ihigh < ilow) ihigh = ilow; - else if ((size_t)ihigh > self->size) + else if (ihigh > self->size) ihigh = self->size; return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow); @@ -780,7 +776,7 @@ return NULL; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; @@ -850,13 +846,13 @@ CHECK_VALID(-1); if (ilow < 0) ilow = 0; - else if ((size_t)ilow > self->size) + else if (ilow > self->size) ilow = self->size; if (ihigh < 0) ihigh = 0; if (ihigh < ilow) ihigh = ilow; - else if ((size_t)ihigh > self->size) + else if (ihigh > self->size) ihigh = self->size; if (v == NULL) { @@ -887,7 +883,7 @@ const char *buf; CHECK_VALID(-1); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } @@ -921,7 +917,7 @@ return -1; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; @@ -1092,32 +1088,6 @@ }; -/* extract the map size from the given PyObject - - Returns -1 on error, with an appropriate Python exception raised. On - success, the map size is returned. */ -static Py_ssize_t -_GetMapSize(PyObject *o, const char* param) -{ - if (o == NULL) - return 0; - if (PyIndex_Check(o)) { - Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError); - if (i==-1 && PyErr_Occurred()) - return -1; - if (i < 0) { - PyErr_Format(PyExc_OverflowError, - "memory mapped %s must be positive", - param); - return -1; - } - return i; - } - - PyErr_SetString(PyExc_TypeError, "map size must be an integral value"); - return -1; -} - #ifdef UNIX #ifdef HAVE_LARGEFILE_SUPPORT #define _Py_PARSE_OFF_T "L" @@ -1132,7 +1102,6 @@ struct stat st; #endif mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; off_t offset = 0; int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; @@ -1142,13 +1111,15 @@ "flags", "prot", "access", "offset", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords, - &fd, &map_size_obj, &flags, &prot, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, + &fd, &map_size, &flags, &prot, &access, &offset)) return NULL; - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); @@ -1220,7 +1191,7 @@ return NULL; } map_size = (Py_ssize_t) (st.st_size - offset); - } else if (offset + (size_t)map_size > st.st_size) { + } else if (offset > st.st_size || st.st_size - offset < map_size) { PyErr_SetString(PyExc_ValueError, "mmap length is greater than file size"); return NULL; @@ -1230,8 +1201,8 @@ m_obj = (mmap_object *)type->tp_alloc(type, 0); if (m_obj == NULL) {return NULL;} m_obj->data = NULL; - m_obj->size = (size_t) map_size; - m_obj->pos = (size_t) 0; + m_obj->size = map_size; + m_obj->pos = 0; m_obj->offset = offset; if (fd == -1) { m_obj->fd = -1; @@ -1290,7 +1261,6 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) { mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; PY_LONG_LONG offset = 0, size; DWORD off_hi; /* upper 32 bits of offset */ @@ -1307,8 +1277,8 @@ "tagname", "access", "offset", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords, - &fileno, &map_size_obj, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, + &fileno, &map_size, &tagname, &access, &offset)) { return NULL; } @@ -1331,9 +1301,11 @@ "mmap invalid access parameter."); } - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:00:13 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:00:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_skip_test_if_r?= =?utf-8?q?esizing_is_not_supported?= Message-ID: <20161006050012.79404.76662.88BDFCF8@psf.io> https://hg.python.org/cpython/rev/48797808a302 changeset: 104318:48797808a302 branch: 2.7 user: Benjamin Peterson date: Wed Oct 05 22:00:05 2016 -0700 summary: skip test if resizing is not supported files: Lib/test/test_mmap.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -656,9 +656,12 @@ m = mmap.mmap(-1, 8192) self.addCleanup(m.close) m.read(5000) - m.resize(4096) + try: + m.resize(4096) + except SystemError: + self.skipTest("resizing not supported") self.assertEqual(m.read(14), '') - self.assertRaises(ValueError, m.read_byte,) + self.assertRaises(ValueError, m.read_byte,1) self.assertRaises(ValueError, m.write_byte, 'b') self.assertRaises(ValueError, m.write, 'abc') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:00:31 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:00:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_fix_bug_in_487?= =?utf-8?q?97808a302?= Message-ID: <20161006050031.17589.36493.FAC4532B@psf.io> https://hg.python.org/cpython/rev/2a2c54a9a7f7 changeset: 104319:2a2c54a9a7f7 branch: 2.7 user: Benjamin Peterson date: Wed Oct 05 22:00:24 2016 -0700 summary: fix bug in 48797808a302 files: Lib/test/test_mmap.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -661,7 +661,7 @@ except SystemError: self.skipTest("resizing not supported") self.assertEqual(m.read(14), '') - self.assertRaises(ValueError, m.read_byte,1) + self.assertRaises(ValueError, m.read_byte) self.assertRaises(ValueError, m.write_byte, 'b') self.assertRaises(ValueError, m.write, 'abc') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:09:37 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:09:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_skip_test_on_w?= =?utf-8?q?indows?= Message-ID: <20161006050936.5035.73866.056827CD@psf.io> https://hg.python.org/cpython/rev/6f62106f7045 changeset: 104320:6f62106f7045 branch: 2.7 user: Benjamin Peterson date: Wed Oct 05 22:09:31 2016 -0700 summary: skip test on windows files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -652,6 +652,7 @@ finally: s.close() + @unittest.skipIf(os.name == 'nt', 'cannot resize anonymous mmaps on Windows') def test_resize_past_pos(self): m = mmap.mmap(-1, 8192) self.addCleanup(m.close) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:54:37 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:54:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_skip_test_if_r?= =?utf-8?q?esizing_is_not_supported?= Message-ID: <20161006055437.15228.40056.F2997F37@psf.io> https://hg.python.org/cpython/rev/a2c0a2a41a3a changeset: 104322:a2c0a2a41a3a branch: 3.5 user: Benjamin Peterson date: Wed Oct 05 22:00:05 2016 -0700 summary: skip test if resizing is not supported files: Lib/test/test_mmap.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -717,7 +717,10 @@ m = mmap.mmap(-1, 8192) self.addCleanup(m.close) m.read(5000) - m.resize(4096) + try: + m.resize(4096) + except SystemError: + self.skipTest("resizing not supported") self.assertEqual(m.read(14), b'') self.assertRaises(ValueError, m.read_byte,) self.assertRaises(ValueError, m.write_byte, 42) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:54:37 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:54:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_fix_bug_in_487?= =?utf-8?q?97808a302?= Message-ID: <20161006055437.79384.60919.64300A20@psf.io> https://hg.python.org/cpython/rev/453eb9e4bf2b changeset: 104323:453eb9e4bf2b branch: 3.5 user: Benjamin Peterson date: Wed Oct 05 22:00:24 2016 -0700 summary: fix bug in 48797808a302 files: Lib/test/test_mmap.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -722,7 +722,7 @@ except SystemError: self.skipTest("resizing not supported") self.assertEqual(m.read(14), b'') - self.assertRaises(ValueError, m.read_byte,) + self.assertRaises(ValueError, m.read_byte) self.assertRaises(ValueError, m.write_byte, 42) self.assertRaises(ValueError, m.write, b'abc') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:54:38 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:54:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_skip_test_on_w?= =?utf-8?q?indows?= Message-ID: <20161006055438.79613.19960.600846CB@psf.io> https://hg.python.org/cpython/rev/c39ab06feacc changeset: 104324:c39ab06feacc branch: 3.5 user: Benjamin Peterson date: Wed Oct 05 22:09:31 2016 -0700 summary: skip test on windows files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -713,6 +713,7 @@ gc_collect() self.assertIs(wr(), None) + @unittest.skipIf(os.name == 'nt', 'cannot resize anonymous mmaps on Windows') def test_resize_past_pos(self): m = mmap.mmap(-1, 8192) self.addCleanup(m.close) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:54:37 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:54:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogbW1hcDogZG8gYWxs?= =?utf-8?q?_internal_arithmetic_with_Py=5Fssize=5Ft_while_being_very_caref?= =?utf-8?q?ul_about?= Message-ID: <20161006055437.85635.42687.62E6FA1A@psf.io> https://hg.python.org/cpython/rev/ee73afc39f3e changeset: 104321:ee73afc39f3e branch: 3.5 parent: 104314:3771a6326725 user: Benjamin Peterson date: Wed Oct 05 21:45:48 2016 -0700 summary: mmap: do all internal arithmetic with Py_ssize_t while being very careful about overflow files: Lib/test/test_mmap.py | 11 + Misc/NEWS | 3 + Modules/mmapmodule.c | 189 ++++++++++++----------------- 3 files changed, 93 insertions(+), 110 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -713,6 +713,17 @@ gc_collect() self.assertIs(wr(), None) + def test_resize_past_pos(self): + m = mmap.mmap(-1, 8192) + self.addCleanup(m.close) + m.read(5000) + m.resize(4096) + self.assertEqual(m.read(14), b'') + self.assertRaises(ValueError, m.read_byte,) + self.assertRaises(ValueError, m.write_byte, 42) + self.assertRaises(ValueError, m.write, b'abc') + + class LargeMmapTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -94,6 +94,9 @@ - Issue #28322: Fixed possible crashes when unpickle itertools objects from incorrect pickle data. Based on patch by John Leitch. +- Fix possible integer overflows and crashes in the mmap module with unusual + usage patterns. + - Issue #1703178: Fix the ability to pass the --link-objects option to the distutils build_ext command. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -90,8 +90,8 @@ typedef struct { PyObject_HEAD char * data; - size_t size; - size_t pos; /* relative to offset */ + Py_ssize_t size; + Py_ssize_t pos; /* relative to offset */ #ifdef MS_WINDOWS PY_LONG_LONG offset; #else @@ -210,33 +210,32 @@ PyObject *unused) { CHECK_VALID(NULL); - if (self->pos < self->size) { - char value = self->data[self->pos]; - self->pos += 1; - return Py_BuildValue("B", (unsigned char)value); - } else { + if (self->pos >= self->size) { PyErr_SetString(PyExc_ValueError, "read byte out of range"); return NULL; } + return PyLong_FromLong((unsigned char)self->data[self->pos++]); } static PyObject * mmap_read_line_method(mmap_object *self, PyObject *unused) { - char *start = self->data+self->pos; - char *eof = self->data+self->size; - char *eol; + Py_ssize_t remaining; + char *start, *eol; PyObject *result; CHECK_VALID(NULL); - eol = memchr(start, '\n', self->size - self->pos); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (!remaining) + return PyBytes_FromString(""); + start = self->data + self->pos; + eol = memchr(start, '\n', remaining); if (!eol) - eol = eof; + eol = self->data + self->size; else - ++eol; /* we're interested in the position after the - newline. */ + ++eol; /* advance past newline */ result = PyBytes_FromStringAndSize(start, (eol - start)); self->pos += (eol - start); return result; @@ -268,7 +267,7 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes = -1, n; + Py_ssize_t num_bytes, remaining; PyObject *result; CHECK_VALID(NULL); @@ -276,20 +275,10 @@ return(NULL); /* silently 'adjust' out-of-range requests */ - assert(self->size >= self->pos); - n = self->size - self->pos; - /* The difference can overflow, only if self->size is greater than - * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed, - * because the mapped area and the returned string each need more - * than half of the addressable memory. So we clip the size, and let - * the code below raise MemoryError. - */ - if (n < 0) - n = PY_SSIZE_T_MAX; - if (num_bytes < 0 || num_bytes > n) { - num_bytes = n; - } - result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (num_bytes < 0 || num_bytes > remaining) + num_bytes = remaining; + result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes); self->pos += num_bytes; return result; } @@ -317,14 +306,14 @@ start += self->size; if (start < 0) start = 0; - else if ((size_t)start > self->size) + else if (start > self->size) start = self->size; if (end < 0) end += self->size; if (end < 0) end = 0; - else if ((size_t)end > self->size) + else if (end > self->size) end = self->size; start_p = self->data + start; @@ -394,18 +383,17 @@ if (!PyArg_ParseTuple(args, "y*:write", &data)) return(NULL); - if (!is_writable(self)) { + if (!is_writable(self)) + return NULL; + + if (self->pos > self->size || self->size - self->pos < data.len) { PyBuffer_Release(&data); + PyErr_SetString(PyExc_ValueError, "data out of range"); return NULL; } - if ((self->pos + data.len) > self->size) { - PyErr_SetString(PyExc_ValueError, "data out of range"); - PyBuffer_Release(&data); - return NULL; - } - memcpy(self->data + self->pos, data.buf, data.len); - self->pos = self->pos + data.len; + memcpy(&self->data[self->pos], data.buf, data.len); + self->pos += data.len; PyBuffer_Release(&data); Py_INCREF(Py_None); return Py_None; @@ -425,8 +413,7 @@ return NULL; if (self->pos < self->size) { - *(self->data+self->pos) = value; - self->pos += 1; + self->data[self->pos++] = value; Py_INCREF(Py_None); return Py_None; } @@ -495,8 +482,14 @@ if (!PyArg_ParseTuple(args, "n:resize", &new_size) || !is_resizeable(self)) { return NULL; + } + if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { + PyErr_SetString(PyExc_ValueError, "new size out of range"); + return NULL; + } + + { #ifdef MS_WINDOWS - } else { DWORD dwErrCode = 0; DWORD off_hi, off_lo, newSizeLow, newSizeHigh; /* First, unmap the file view */ @@ -546,15 +539,13 @@ #ifdef UNIX #ifndef HAVE_MREMAP - } else { PyErr_SetString(PyExc_SystemError, "mmap: resizing not available--no mremap()"); return NULL; #else - } else { void *newmap; - if (ftruncate(self->fd, self->offset + new_size) == -1) { + if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -562,11 +553,11 @@ #ifdef MREMAP_MAYMOVE newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); #else - #if defined(__NetBSD__) - newmap = mremap(self->data, self->size, self->data, new_size, 0); - #else - newmap = mremap(self->data, self->size, new_size, 0); - #endif /* __NetBSD__ */ +#if defined(__NetBSD__) + newmap = mremap(self->data, self->size, self->data, new_size, 0); +#else + newmap = mremap(self->data, self->size, new_size, 0); +#endif /* __NetBSD__ */ #endif if (newmap == (void *)-1) { @@ -597,7 +588,7 @@ CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) return NULL; - if ((size_t)(offset + size) > self->size) { + if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; } @@ -630,20 +621,18 @@ if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) return NULL; else { - size_t where; + Py_ssize_t where; switch (how) { case 0: /* relative to start */ - if (dist < 0) - goto onoutofrange; where = dist; break; case 1: /* relative to current position */ - if ((Py_ssize_t)self->pos + dist < 0) + if (PY_SSIZE_T_MAX - self->pos < dist) goto onoutofrange; where = self->pos + dist; break; case 2: /* relative to end */ - if ((Py_ssize_t)self->size + dist < 0) + if (PY_SSIZE_T_MAX - self->size < dist) goto onoutofrange; where = self->size + dist; break; @@ -651,7 +640,7 @@ PyErr_SetString(PyExc_ValueError, "unknown seek type"); return NULL; } - if (where > self->size) + if (where > self->size || where < 0) goto onoutofrange; self->pos = where; Py_INCREF(Py_None); @@ -666,23 +655,27 @@ static PyObject * mmap_move_method(mmap_object *self, PyObject *args) { - unsigned long dest, src, cnt; + Py_ssize_t dest, src, cnt; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) || + if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || !is_writable(self)) { return NULL; } else { /* bounds check the values */ - if ((cnt + dest) < cnt || (cnt + src) < cnt || - src > self->size || (src + cnt) > self->size || - dest > self->size || (dest + cnt) > self->size) { - PyErr_SetString(PyExc_ValueError, - "source, destination, or count out of range"); - return NULL; - } - memmove(self->data+dest, self->data+src, cnt); + if (dest < 0 || src < 0 || cnt < 0) + goto bounds; + if (self->size - dest < cnt || self->size - src < cnt) + goto bounds; + + memmove(&self->data[dest], &self->data[src], cnt); + Py_INCREF(Py_None); return Py_None; + + bounds: + PyErr_SetString(PyExc_ValueError, + "source, destination, or count out of range"); + return NULL; } } @@ -785,7 +778,7 @@ mmap_item(mmap_object *self, Py_ssize_t i) { CHECK_VALID(NULL); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } @@ -802,7 +795,7 @@ return NULL; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; @@ -870,7 +863,7 @@ const char *buf; CHECK_VALID(-1); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } @@ -907,7 +900,7 @@ return -1; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; @@ -1074,32 +1067,6 @@ }; -/* extract the map size from the given PyObject - - Returns -1 on error, with an appropriate Python exception raised. On - success, the map size is returned. */ -static Py_ssize_t -_GetMapSize(PyObject *o, const char* param) -{ - if (o == NULL) - return 0; - if (PyIndex_Check(o)) { - Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError); - if (i==-1 && PyErr_Occurred()) - return -1; - if (i < 0) { - PyErr_Format(PyExc_OverflowError, - "memory mapped %s must be positive", - param); - return -1; - } - return i; - } - - PyErr_SetString(PyExc_TypeError, "map size must be an integral value"); - return -1; -} - #ifdef UNIX #ifdef HAVE_LARGEFILE_SUPPORT #define _Py_PARSE_OFF_T "L" @@ -1112,7 +1079,6 @@ { struct _Py_stat_struct status; mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; off_t offset = 0; int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; @@ -1122,13 +1088,15 @@ "flags", "prot", "access", "offset", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords, - &fd, &map_size_obj, &flags, &prot, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, + &fd, &map_size, &flags, &prot, &access, &offset)) return NULL; - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); @@ -1194,7 +1162,7 @@ return NULL; } map_size = (Py_ssize_t) (status.st_size - offset); - } else if (offset + map_size > status.st_size) { + } else if (offset > status.st_size || status.st_size - offset < map_size) { PyErr_SetString(PyExc_ValueError, "mmap length is greater than file size"); return NULL; @@ -1203,8 +1171,8 @@ m_obj = (mmap_object *)type->tp_alloc(type, 0); if (m_obj == NULL) {return NULL;} m_obj->data = NULL; - m_obj->size = (size_t) map_size; - m_obj->pos = (size_t) 0; + m_obj->size = map_size; + m_obj->pos = 0; m_obj->weakreflist = NULL; m_obj->exports = 0; m_obj->offset = offset; @@ -1264,7 +1232,6 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) { mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; PY_LONG_LONG offset = 0, size; DWORD off_hi; /* upper 32 bits of offset */ @@ -1281,8 +1248,8 @@ "tagname", "access", "offset", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords, - &fileno, &map_size_obj, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, + &fileno, &map_size, &tagname, &access, &offset)) { return NULL; } @@ -1305,9 +1272,11 @@ "mmap invalid access parameter."); } - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:54:38 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:54:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_merge_3=2E5?= Message-ID: <20161006055438.82256.76232.73A36909@psf.io> https://hg.python.org/cpython/rev/5d62945392fb changeset: 104325:5d62945392fb branch: 3.6 parent: 104315:3e6739e5c2d0 parent: 104324:c39ab06feacc user: Benjamin Peterson date: Wed Oct 05 22:54:19 2016 -0700 summary: merge 3.5 files: Lib/test/test_mmap.py | 14 ++ Misc/NEWS | 3 + Modules/mmapmodule.c | 193 ++++++++++++----------------- 3 files changed, 97 insertions(+), 113 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -720,6 +720,20 @@ self.assertEqual(mm.write(b"yz"), 2) self.assertEqual(mm.write(b"python"), 6) + @unittest.skipIf(os.name == 'nt', 'cannot resize anonymous mmaps on Windows') + def test_resize_past_pos(self): + m = mmap.mmap(-1, 8192) + self.addCleanup(m.close) + m.read(5000) + try: + m.resize(4096) + except SystemError: + self.skipTest("resizing not supported") + self.assertEqual(m.read(14), b'') + self.assertRaises(ValueError, m.read_byte) + self.assertRaises(ValueError, m.write_byte, 42) + self.assertRaises(ValueError, m.write, b'abc') + class LargeMmapTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -404,6 +404,9 @@ pickling and text representation purposes. Patch by Emanuel Barry and Serhiy Storchaka. +- Fix possible integer overflows and crashes in the mmap module with unusual + usage patterns. + - Issue #1703178: Fix the ability to pass the --link-objects option to the distutils build_ext command. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -90,8 +90,8 @@ typedef struct { PyObject_HEAD char * data; - size_t size; - size_t pos; /* relative to offset */ + Py_ssize_t size; + Py_ssize_t pos; /* relative to offset */ #ifdef MS_WINDOWS long long offset; #else @@ -210,33 +210,32 @@ PyObject *unused) { CHECK_VALID(NULL); - if (self->pos < self->size) { - char value = self->data[self->pos]; - self->pos += 1; - return Py_BuildValue("B", (unsigned char)value); - } else { + if (self->pos >= self->size) { PyErr_SetString(PyExc_ValueError, "read byte out of range"); return NULL; } + return PyLong_FromLong((unsigned char)self->data[self->pos++]); } static PyObject * mmap_read_line_method(mmap_object *self, PyObject *unused) { - char *start = self->data+self->pos; - char *eof = self->data+self->size; - char *eol; + Py_ssize_t remaining; + char *start, *eol; PyObject *result; CHECK_VALID(NULL); - eol = memchr(start, '\n', self->size - self->pos); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (!remaining) + return PyBytes_FromString(""); + start = self->data + self->pos; + eol = memchr(start, '\n', remaining); if (!eol) - eol = eof; + eol = self->data + self->size; else - ++eol; /* we're interested in the position after the - newline. */ + ++eol; /* advance past newline */ result = PyBytes_FromStringAndSize(start, (eol - start)); self->pos += (eol - start); return result; @@ -268,7 +267,7 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes = -1, n; + Py_ssize_t num_bytes, remaining; PyObject *result; CHECK_VALID(NULL); @@ -276,20 +275,10 @@ return(NULL); /* silently 'adjust' out-of-range requests */ - assert(self->size >= self->pos); - n = self->size - self->pos; - /* The difference can overflow, only if self->size is greater than - * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed, - * because the mapped area and the returned string each need more - * than half of the addressable memory. So we clip the size, and let - * the code below raise MemoryError. - */ - if (n < 0) - n = PY_SSIZE_T_MAX; - if (num_bytes < 0 || num_bytes > n) { - num_bytes = n; - } - result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (num_bytes < 0 || num_bytes > remaining) + num_bytes = remaining; + result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes); self->pos += num_bytes; return result; } @@ -317,14 +306,14 @@ start += self->size; if (start < 0) start = 0; - else if ((size_t)start > self->size) + else if (start > self->size) start = self->size; if (end < 0) end += self->size; if (end < 0) end = 0; - else if ((size_t)end > self->size) + else if (end > self->size) end = self->size; start_p = self->data + start; @@ -389,27 +378,24 @@ PyObject *args) { Py_buffer data; - PyObject *result; CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "y*:write", &data)) return(NULL); - if (!is_writable(self)) { + if (!is_writable(self)) + return NULL; + + if (self->pos > self->size || self->size - self->pos < data.len) { PyBuffer_Release(&data); + PyErr_SetString(PyExc_ValueError, "data out of range"); return NULL; } - if ((self->pos + data.len) > self->size) { - PyErr_SetString(PyExc_ValueError, "data out of range"); - PyBuffer_Release(&data); - return NULL; - } - memcpy(self->data + self->pos, data.buf, data.len); - self->pos = self->pos + data.len; - result = PyLong_FromSsize_t(data.len); + memcpy(&self->data[self->pos], data.buf, data.len); + self->pos += data.len; PyBuffer_Release(&data); - return result; + return PyLong_FromSsize_t(data.len); } static PyObject * @@ -426,8 +412,7 @@ return NULL; if (self->pos < self->size) { - *(self->data+self->pos) = value; - self->pos += 1; + self->data[self->pos++] = value; Py_INCREF(Py_None); return Py_None; } @@ -496,8 +481,14 @@ if (!PyArg_ParseTuple(args, "n:resize", &new_size) || !is_resizeable(self)) { return NULL; + } + if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { + PyErr_SetString(PyExc_ValueError, "new size out of range"); + return NULL; + } + + { #ifdef MS_WINDOWS - } else { DWORD dwErrCode = 0; DWORD off_hi, off_lo, newSizeLow, newSizeHigh; /* First, unmap the file view */ @@ -547,15 +538,13 @@ #ifdef UNIX #ifndef HAVE_MREMAP - } else { PyErr_SetString(PyExc_SystemError, "mmap: resizing not available--no mremap()"); return NULL; #else - } else { void *newmap; - if (ftruncate(self->fd, self->offset + new_size) == -1) { + if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -563,11 +552,11 @@ #ifdef MREMAP_MAYMOVE newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); #else - #if defined(__NetBSD__) - newmap = mremap(self->data, self->size, self->data, new_size, 0); - #else - newmap = mremap(self->data, self->size, new_size, 0); - #endif /* __NetBSD__ */ +#if defined(__NetBSD__) + newmap = mremap(self->data, self->size, self->data, new_size, 0); +#else + newmap = mremap(self->data, self->size, new_size, 0); +#endif /* __NetBSD__ */ #endif if (newmap == (void *)-1) { @@ -598,7 +587,7 @@ CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) return NULL; - if ((size_t)(offset + size) > self->size) { + if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; } @@ -631,20 +620,18 @@ if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) return NULL; else { - size_t where; + Py_ssize_t where; switch (how) { case 0: /* relative to start */ - if (dist < 0) - goto onoutofrange; where = dist; break; case 1: /* relative to current position */ - if ((Py_ssize_t)self->pos + dist < 0) + if (PY_SSIZE_T_MAX - self->pos < dist) goto onoutofrange; where = self->pos + dist; break; case 2: /* relative to end */ - if ((Py_ssize_t)self->size + dist < 0) + if (PY_SSIZE_T_MAX - self->size < dist) goto onoutofrange; where = self->size + dist; break; @@ -652,7 +639,7 @@ PyErr_SetString(PyExc_ValueError, "unknown seek type"); return NULL; } - if (where > self->size) + if (where > self->size || where < 0) goto onoutofrange; self->pos = where; Py_INCREF(Py_None); @@ -667,23 +654,27 @@ static PyObject * mmap_move_method(mmap_object *self, PyObject *args) { - unsigned long dest, src, cnt; + Py_ssize_t dest, src, cnt; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) || + if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || !is_writable(self)) { return NULL; } else { /* bounds check the values */ - if ((cnt + dest) < cnt || (cnt + src) < cnt || - src > self->size || (src + cnt) > self->size || - dest > self->size || (dest + cnt) > self->size) { - PyErr_SetString(PyExc_ValueError, - "source, destination, or count out of range"); - return NULL; - } - memmove(self->data+dest, self->data+src, cnt); + if (dest < 0 || src < 0 || cnt < 0) + goto bounds; + if (self->size - dest < cnt || self->size - src < cnt) + goto bounds; + + memmove(&self->data[dest], &self->data[src], cnt); + Py_INCREF(Py_None); return Py_None; + + bounds: + PyErr_SetString(PyExc_ValueError, + "source, destination, or count out of range"); + return NULL; } } @@ -786,7 +777,7 @@ mmap_item(mmap_object *self, Py_ssize_t i) { CHECK_VALID(NULL); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } @@ -803,7 +794,7 @@ return NULL; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; @@ -871,7 +862,7 @@ const char *buf; CHECK_VALID(-1); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } @@ -908,7 +899,7 @@ return -1; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; @@ -1075,32 +1066,6 @@ }; -/* extract the map size from the given PyObject - - Returns -1 on error, with an appropriate Python exception raised. On - success, the map size is returned. */ -static Py_ssize_t -_GetMapSize(PyObject *o, const char* param) -{ - if (o == NULL) - return 0; - if (PyIndex_Check(o)) { - Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError); - if (i==-1 && PyErr_Occurred()) - return -1; - if (i < 0) { - PyErr_Format(PyExc_OverflowError, - "memory mapped %s must be positive", - param); - return -1; - } - return i; - } - - PyErr_SetString(PyExc_TypeError, "map size must be an integral value"); - return -1; -} - #ifdef UNIX #ifdef HAVE_LARGEFILE_SUPPORT #define _Py_PARSE_OFF_T "L" @@ -1113,7 +1078,6 @@ { struct _Py_stat_struct status; mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; off_t offset = 0; int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; @@ -1123,13 +1087,15 @@ "flags", "prot", "access", "offset", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords, - &fd, &map_size_obj, &flags, &prot, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, + &fd, &map_size, &flags, &prot, &access, &offset)) return NULL; - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); @@ -1195,7 +1161,7 @@ return NULL; } map_size = (Py_ssize_t) (status.st_size - offset); - } else if (offset + map_size > status.st_size) { + } else if (offset > status.st_size || status.st_size - offset < map_size) { PyErr_SetString(PyExc_ValueError, "mmap length is greater than file size"); return NULL; @@ -1204,8 +1170,8 @@ m_obj = (mmap_object *)type->tp_alloc(type, 0); if (m_obj == NULL) {return NULL;} m_obj->data = NULL; - m_obj->size = (size_t) map_size; - m_obj->pos = (size_t) 0; + m_obj->size = map_size; + m_obj->pos = 0; m_obj->weakreflist = NULL; m_obj->exports = 0; m_obj->offset = offset; @@ -1265,7 +1231,6 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) { mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; long long offset = 0, size; DWORD off_hi; /* upper 32 bits of offset */ @@ -1282,8 +1247,8 @@ "tagname", "access", "offset", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords, - &fileno, &map_size_obj, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, + &fileno, &map_size, &tagname, &access, &offset)) { return NULL; } @@ -1306,9 +1271,11 @@ "mmap invalid access parameter."); } - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 01:54:38 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 05:54:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161006055438.75822.22735.7A434167@psf.io> https://hg.python.org/cpython/rev/d1c72f5c15bd changeset: 104326:d1c72f5c15bd parent: 104316:f2204eaba685 parent: 104325:5d62945392fb user: Benjamin Peterson date: Wed Oct 05 22:54:27 2016 -0700 summary: merge 3.6 files: Lib/test/test_mmap.py | 14 ++ Misc/NEWS | 3 + Modules/mmapmodule.c | 193 ++++++++++++----------------- 3 files changed, 97 insertions(+), 113 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -720,6 +720,20 @@ self.assertEqual(mm.write(b"yz"), 2) self.assertEqual(mm.write(b"python"), 6) + @unittest.skipIf(os.name == 'nt', 'cannot resize anonymous mmaps on Windows') + def test_resize_past_pos(self): + m = mmap.mmap(-1, 8192) + self.addCleanup(m.close) + m.read(5000) + try: + m.resize(4096) + except SystemError: + self.skipTest("resizing not supported") + self.assertEqual(m.read(14), b'') + self.assertRaises(ValueError, m.read_byte) + self.assertRaises(ValueError, m.write_byte, 42) + self.assertRaises(ValueError, m.write, b'abc') + class LargeMmapTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -441,6 +441,9 @@ pickling and text representation purposes. Patch by Emanuel Barry and Serhiy Storchaka. +- Fix possible integer overflows and crashes in the mmap module with unusual + usage patterns. + - Issue #1703178: Fix the ability to pass the --link-objects option to the distutils build_ext command. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -90,8 +90,8 @@ typedef struct { PyObject_HEAD char * data; - size_t size; - size_t pos; /* relative to offset */ + Py_ssize_t size; + Py_ssize_t pos; /* relative to offset */ #ifdef MS_WINDOWS long long offset; #else @@ -210,33 +210,32 @@ PyObject *unused) { CHECK_VALID(NULL); - if (self->pos < self->size) { - char value = self->data[self->pos]; - self->pos += 1; - return Py_BuildValue("B", (unsigned char)value); - } else { + if (self->pos >= self->size) { PyErr_SetString(PyExc_ValueError, "read byte out of range"); return NULL; } + return PyLong_FromLong((unsigned char)self->data[self->pos++]); } static PyObject * mmap_read_line_method(mmap_object *self, PyObject *unused) { - char *start = self->data+self->pos; - char *eof = self->data+self->size; - char *eol; + Py_ssize_t remaining; + char *start, *eol; PyObject *result; CHECK_VALID(NULL); - eol = memchr(start, '\n', self->size - self->pos); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (!remaining) + return PyBytes_FromString(""); + start = self->data + self->pos; + eol = memchr(start, '\n', remaining); if (!eol) - eol = eof; + eol = self->data + self->size; else - ++eol; /* we're interested in the position after the - newline. */ + ++eol; /* advance past newline */ result = PyBytes_FromStringAndSize(start, (eol - start)); self->pos += (eol - start); return result; @@ -268,7 +267,7 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes = -1, n; + Py_ssize_t num_bytes, remaining; PyObject *result; CHECK_VALID(NULL); @@ -276,20 +275,10 @@ return(NULL); /* silently 'adjust' out-of-range requests */ - assert(self->size >= self->pos); - n = self->size - self->pos; - /* The difference can overflow, only if self->size is greater than - * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed, - * because the mapped area and the returned string each need more - * than half of the addressable memory. So we clip the size, and let - * the code below raise MemoryError. - */ - if (n < 0) - n = PY_SSIZE_T_MAX; - if (num_bytes < 0 || num_bytes > n) { - num_bytes = n; - } - result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes); + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (num_bytes < 0 || num_bytes > remaining) + num_bytes = remaining; + result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes); self->pos += num_bytes; return result; } @@ -317,14 +306,14 @@ start += self->size; if (start < 0) start = 0; - else if ((size_t)start > self->size) + else if (start > self->size) start = self->size; if (end < 0) end += self->size; if (end < 0) end = 0; - else if ((size_t)end > self->size) + else if (end > self->size) end = self->size; start_p = self->data + start; @@ -389,27 +378,24 @@ PyObject *args) { Py_buffer data; - PyObject *result; CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "y*:write", &data)) return(NULL); - if (!is_writable(self)) { + if (!is_writable(self)) + return NULL; + + if (self->pos > self->size || self->size - self->pos < data.len) { PyBuffer_Release(&data); + PyErr_SetString(PyExc_ValueError, "data out of range"); return NULL; } - if ((self->pos + data.len) > self->size) { - PyErr_SetString(PyExc_ValueError, "data out of range"); - PyBuffer_Release(&data); - return NULL; - } - memcpy(self->data + self->pos, data.buf, data.len); - self->pos = self->pos + data.len; - result = PyLong_FromSsize_t(data.len); + memcpy(&self->data[self->pos], data.buf, data.len); + self->pos += data.len; PyBuffer_Release(&data); - return result; + return PyLong_FromSsize_t(data.len); } static PyObject * @@ -426,8 +412,7 @@ return NULL; if (self->pos < self->size) { - *(self->data+self->pos) = value; - self->pos += 1; + self->data[self->pos++] = value; Py_INCREF(Py_None); return Py_None; } @@ -496,8 +481,14 @@ if (!PyArg_ParseTuple(args, "n:resize", &new_size) || !is_resizeable(self)) { return NULL; + } + if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { + PyErr_SetString(PyExc_ValueError, "new size out of range"); + return NULL; + } + + { #ifdef MS_WINDOWS - } else { DWORD dwErrCode = 0; DWORD off_hi, off_lo, newSizeLow, newSizeHigh; /* First, unmap the file view */ @@ -547,15 +538,13 @@ #ifdef UNIX #ifndef HAVE_MREMAP - } else { PyErr_SetString(PyExc_SystemError, "mmap: resizing not available--no mremap()"); return NULL; #else - } else { void *newmap; - if (ftruncate(self->fd, self->offset + new_size) == -1) { + if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -563,11 +552,11 @@ #ifdef MREMAP_MAYMOVE newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); #else - #if defined(__NetBSD__) - newmap = mremap(self->data, self->size, self->data, new_size, 0); - #else - newmap = mremap(self->data, self->size, new_size, 0); - #endif /* __NetBSD__ */ +#if defined(__NetBSD__) + newmap = mremap(self->data, self->size, self->data, new_size, 0); +#else + newmap = mremap(self->data, self->size, new_size, 0); +#endif /* __NetBSD__ */ #endif if (newmap == (void *)-1) { @@ -598,7 +587,7 @@ CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) return NULL; - if ((size_t)(offset + size) > self->size) { + if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; } @@ -631,20 +620,18 @@ if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) return NULL; else { - size_t where; + Py_ssize_t where; switch (how) { case 0: /* relative to start */ - if (dist < 0) - goto onoutofrange; where = dist; break; case 1: /* relative to current position */ - if ((Py_ssize_t)self->pos + dist < 0) + if (PY_SSIZE_T_MAX - self->pos < dist) goto onoutofrange; where = self->pos + dist; break; case 2: /* relative to end */ - if ((Py_ssize_t)self->size + dist < 0) + if (PY_SSIZE_T_MAX - self->size < dist) goto onoutofrange; where = self->size + dist; break; @@ -652,7 +639,7 @@ PyErr_SetString(PyExc_ValueError, "unknown seek type"); return NULL; } - if (where > self->size) + if (where > self->size || where < 0) goto onoutofrange; self->pos = where; Py_INCREF(Py_None); @@ -667,23 +654,27 @@ static PyObject * mmap_move_method(mmap_object *self, PyObject *args) { - unsigned long dest, src, cnt; + Py_ssize_t dest, src, cnt; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) || + if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || !is_writable(self)) { return NULL; } else { /* bounds check the values */ - if ((cnt + dest) < cnt || (cnt + src) < cnt || - src > self->size || (src + cnt) > self->size || - dest > self->size || (dest + cnt) > self->size) { - PyErr_SetString(PyExc_ValueError, - "source, destination, or count out of range"); - return NULL; - } - memmove(self->data+dest, self->data+src, cnt); + if (dest < 0 || src < 0 || cnt < 0) + goto bounds; + if (self->size - dest < cnt || self->size - src < cnt) + goto bounds; + + memmove(&self->data[dest], &self->data[src], cnt); + Py_INCREF(Py_None); return Py_None; + + bounds: + PyErr_SetString(PyExc_ValueError, + "source, destination, or count out of range"); + return NULL; } } @@ -786,7 +777,7 @@ mmap_item(mmap_object *self, Py_ssize_t i) { CHECK_VALID(NULL); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } @@ -803,7 +794,7 @@ return NULL; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; @@ -871,7 +862,7 @@ const char *buf; CHECK_VALID(-1); - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } @@ -908,7 +899,7 @@ return -1; if (i < 0) i += self->size; - if (i < 0 || (size_t)i >= self->size) { + if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; @@ -1075,32 +1066,6 @@ }; -/* extract the map size from the given PyObject - - Returns -1 on error, with an appropriate Python exception raised. On - success, the map size is returned. */ -static Py_ssize_t -_GetMapSize(PyObject *o, const char* param) -{ - if (o == NULL) - return 0; - if (PyIndex_Check(o)) { - Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError); - if (i==-1 && PyErr_Occurred()) - return -1; - if (i < 0) { - PyErr_Format(PyExc_OverflowError, - "memory mapped %s must be positive", - param); - return -1; - } - return i; - } - - PyErr_SetString(PyExc_TypeError, "map size must be an integral value"); - return -1; -} - #ifdef UNIX #ifdef HAVE_LARGEFILE_SUPPORT #define _Py_PARSE_OFF_T "L" @@ -1113,7 +1078,6 @@ { struct _Py_stat_struct status; mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; off_t offset = 0; int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; @@ -1123,13 +1087,15 @@ "flags", "prot", "access", "offset", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords, - &fd, &map_size_obj, &flags, &prot, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, + &fd, &map_size, &flags, &prot, &access, &offset)) return NULL; - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); @@ -1195,7 +1161,7 @@ return NULL; } map_size = (Py_ssize_t) (status.st_size - offset); - } else if (offset + map_size > status.st_size) { + } else if (offset > status.st_size || status.st_size - offset < map_size) { PyErr_SetString(PyExc_ValueError, "mmap length is greater than file size"); return NULL; @@ -1204,8 +1170,8 @@ m_obj = (mmap_object *)type->tp_alloc(type, 0); if (m_obj == NULL) {return NULL;} m_obj->data = NULL; - m_obj->size = (size_t) map_size; - m_obj->pos = (size_t) 0; + m_obj->size = map_size; + m_obj->pos = 0; m_obj->weakreflist = NULL; m_obj->exports = 0; m_obj->offset = offset; @@ -1265,7 +1231,6 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) { mmap_object *m_obj; - PyObject *map_size_obj = NULL; Py_ssize_t map_size; long long offset = 0, size; DWORD off_hi; /* upper 32 bits of offset */ @@ -1282,8 +1247,8 @@ "tagname", "access", "offset", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords, - &fileno, &map_size_obj, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, + &fileno, &map_size, &tagname, &access, &offset)) { return NULL; } @@ -1306,9 +1271,11 @@ "mmap invalid access parameter."); } - map_size = _GetMapSize(map_size_obj, "size"); - if (map_size < 0) + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be postiive"); return NULL; + } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, "memory mapped offset must be positive"); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:23:22 2016 From: python-checkins at python.org (inada.naoki) Date: Thu, 06 Oct 2016 06:23:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328201=3A_Dict_reduces_possibility_of_2nd_confli?= =?utf-8?q?ct_in_hash_table=2E?= Message-ID: <20161006062322.15207.23124.D06A919D@psf.io> https://hg.python.org/cpython/rev/80b01cd94a63 changeset: 104328:80b01cd94a63 parent: 104326:d1c72f5c15bd parent: 104327:cf2778fd7acb user: INADA Naoki date: Thu Oct 06 15:22:28 2016 +0900 summary: Issue #28201: Dict reduces possibility of 2nd conflict in hash table. Do perturb shift after first conflict. files: Misc/NEWS | 3 ++ Objects/dictobject.c | 38 ++++++++++++++++++------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28201: Dict reduces possibility of 2nd conflict in hash table when + hashes have same lower bits. + - Issue #28350: String constants with null character no longer interned. - Issue #26617: Fix crash when GC runs during weakref callbacks. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -184,8 +184,8 @@ into play. This is done by initializing a (unsigned) vrbl "perturb" to the full hash code, and changing the recurrence to: + perturb >>= PERTURB_SHIFT; j = (5*j) + 1 + perturb; - perturb >>= PERTURB_SHIFT; use j % 2**i as the next table index; Now the probe sequence depends (eventually) on every bit in the hash code, @@ -630,7 +630,7 @@ static Py_ssize_t lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(k); Py_ssize_t ix; @@ -643,7 +643,8 @@ return DKIX_EMPTY; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(k, i); if (ix == index) { @@ -685,7 +686,7 @@ lookdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb, mask; + size_t i, mask; Py_ssize_t ix, freeslot; int cmp; PyDictKeysObject *dk; @@ -740,7 +741,8 @@ freeslot = -1; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = ((i << 2) + i + perturb + 1) & mask; ix = dk_get_index(dk, i); if (ix == DKIX_EMPTY) { @@ -797,7 +799,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix, freeslot; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -835,7 +837,8 @@ freeslot = -1; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(mp->ma_keys, i); if (ix == DKIX_EMPTY) { @@ -872,7 +875,7 @@ Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -905,7 +908,8 @@ *value_addr = &ep->me_value; return ix; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(mp->ma_keys, i); assert (ix != DKIX_DUMMY); @@ -938,7 +942,7 @@ lookdict_split(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -971,7 +975,8 @@ *value_addr = &mp->ma_values[ix]; return ix; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(mp->ma_keys, i); if (ix == DKIX_EMPTY) { @@ -1064,7 +1069,7 @@ find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -1077,7 +1082,8 @@ mp->ma_keys->dk_lookup = lookdict; i = hash & mask; ix = dk_get_index(mp->ma_keys, i); - for (perturb = hash; ix != DKIX_EMPTY; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash; ix != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; i = (i << 2) + i + perturb + 1; ix = dk_get_index(mp->ma_keys, i & mask); } @@ -1202,7 +1208,7 @@ insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) { - size_t i, perturb; + size_t i; PyDictKeysObject *k = mp->ma_keys; size_t mask = (size_t)DK_SIZE(k)-1; PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); @@ -1213,8 +1219,8 @@ assert(key != NULL); assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); i = hash & mask; - for (perturb = hash; dk_get_index(k, i) != DKIX_EMPTY; - perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); } ep = &ep0[k->dk_nentries]; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:23:22 2016 From: python-checkins at python.org (inada.naoki) Date: Thu, 06 Oct 2016 06:23:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjAx?= =?utf-8?q?=3A_Dict_reduces_possibility_of_2nd_conflict_in_hash_table=2E?= Message-ID: <20161006062322.75862.87312.829EE7A7@psf.io> https://hg.python.org/cpython/rev/cf2778fd7acb changeset: 104327:cf2778fd7acb branch: 3.6 parent: 104325:5d62945392fb user: INADA Naoki date: Thu Oct 06 15:19:07 2016 +0900 summary: Issue #28201: Dict reduces possibility of 2nd conflict in hash table. Do perturb shift after first conflict. files: Misc/NEWS | 3 ++ Objects/dictobject.c | 38 ++++++++++++++++++------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28201: Dict reduces possibility of 2nd conflict in hash table when + hashes have same lower bits. + - Issue #28350: String constants with null character no longer interned. - Issue #26617: Fix crash when GC runs during weakref callbacks. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -184,8 +184,8 @@ into play. This is done by initializing a (unsigned) vrbl "perturb" to the full hash code, and changing the recurrence to: + perturb >>= PERTURB_SHIFT; j = (5*j) + 1 + perturb; - perturb >>= PERTURB_SHIFT; use j % 2**i as the next table index; Now the probe sequence depends (eventually) on every bit in the hash code, @@ -630,7 +630,7 @@ static Py_ssize_t lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(k); Py_ssize_t ix; @@ -643,7 +643,8 @@ return DKIX_EMPTY; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(k, i); if (ix == index) { @@ -685,7 +686,7 @@ lookdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb, mask; + size_t i, mask; Py_ssize_t ix, freeslot; int cmp; PyDictKeysObject *dk; @@ -740,7 +741,8 @@ freeslot = -1; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = ((i << 2) + i + perturb + 1) & mask; ix = dk_get_index(dk, i); if (ix == DKIX_EMPTY) { @@ -797,7 +799,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix, freeslot; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -835,7 +837,8 @@ freeslot = -1; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(mp->ma_keys, i); if (ix == DKIX_EMPTY) { @@ -872,7 +875,7 @@ Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -905,7 +908,8 @@ *value_addr = &ep->me_value; return ix; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(mp->ma_keys, i); assert (ix != DKIX_DUMMY); @@ -938,7 +942,7 @@ lookdict_split(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -971,7 +975,8 @@ *value_addr = &mp->ma_values[ix]; return ix; } - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash;;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); ix = dk_get_index(mp->ma_keys, i); if (ix == DKIX_EMPTY) { @@ -1064,7 +1069,7 @@ find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { - size_t i, perturb; + size_t i; size_t mask = DK_MASK(mp->ma_keys); Py_ssize_t ix; PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); @@ -1077,7 +1082,8 @@ mp->ma_keys->dk_lookup = lookdict; i = hash & mask; ix = dk_get_index(mp->ma_keys, i); - for (perturb = hash; ix != DKIX_EMPTY; perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash; ix != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; i = (i << 2) + i + perturb + 1; ix = dk_get_index(mp->ma_keys, i & mask); } @@ -1202,7 +1208,7 @@ insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) { - size_t i, perturb; + size_t i; PyDictKeysObject *k = mp->ma_keys; size_t mask = (size_t)DK_SIZE(k)-1; PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); @@ -1213,8 +1219,8 @@ assert(key != NULL); assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); i = hash & mask; - for (perturb = hash; dk_get_index(k, i) != DKIX_EMPTY; - perturb >>= PERTURB_SHIFT) { + for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; i = mask & ((i << 2) + i + perturb + 1); } ep = &ep0[k->dk_nentries]; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:26:31 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:26:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogbWFrZSAnd2hlcmUn?= =?utf-8?q?_Py=5Fssize=5Ft?= Message-ID: <20161006062631.20849.13395.DC9AF326@psf.io> https://hg.python.org/cpython/rev/59260b38f7cd changeset: 104329:59260b38f7cd branch: 2.7 parent: 104320:6f62106f7045 user: Benjamin Peterson date: Wed Oct 05 23:26:24 2016 -0700 summary: make 'where' Py_ssize_t files: Modules/mmapmodule.c | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -585,11 +585,9 @@ if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) return NULL; else { - size_t where; + Py_ssize_t where; switch (how) { case 0: /* relative to start */ - if (dist < 0) - goto onoutofrange; where = dist; break; case 1: /* relative to current position */ @@ -606,7 +604,7 @@ PyErr_SetString(PyExc_ValueError, "unknown seek type"); return NULL; } - if (where > self->size) + if (where > self->size || where < 0) goto onoutofrange; self->pos = where; Py_INCREF(Py_None); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:29:29 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:29:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_do_not_leak_bu?= =?utf-8?q?ffer_if_mmap_is_not_writable?= Message-ID: <20161006062929.79619.28655.5A35940A@psf.io> https://hg.python.org/cpython/rev/dfb9088f7308 changeset: 104330:dfb9088f7308 branch: 3.5 parent: 104324:c39ab06feacc user: Benjamin Peterson date: Wed Oct 05 23:29:07 2016 -0700 summary: do not leak buffer if mmap is not writable files: Modules/mmapmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -383,8 +383,10 @@ if (!PyArg_ParseTuple(args, "y*:write", &data)) return(NULL); - if (!is_writable(self)) + if (!is_writable(self)) { + PyBuffer_Release(&data); return NULL; + } if (self->pos > self->size || self->size - self->pos < data.len) { PyBuffer_Release(&data); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:29:29 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:29:29 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_merge_3=2E5?= Message-ID: <20161006062929.94902.44897.D714D191@psf.io> https://hg.python.org/cpython/rev/5f1badfc8a99 changeset: 104331:5f1badfc8a99 branch: 3.6 parent: 104327:cf2778fd7acb parent: 104330:dfb9088f7308 user: Benjamin Peterson date: Wed Oct 05 23:29:16 2016 -0700 summary: merge 3.5 files: Modules/mmapmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -383,8 +383,10 @@ if (!PyArg_ParseTuple(args, "y*:write", &data)) return(NULL); - if (!is_writable(self)) + if (!is_writable(self)) { + PyBuffer_Release(&data); return NULL; + } if (self->pos > self->size || self->size - self->pos < data.len) { PyBuffer_Release(&data); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:29:29 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:29:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161006062929.95094.33357.A2B64294@psf.io> https://hg.python.org/cpython/rev/854c89d61536 changeset: 104332:854c89d61536 parent: 104328:80b01cd94a63 parent: 104331:5f1badfc8a99 user: Benjamin Peterson date: Wed Oct 05 23:29:22 2016 -0700 summary: merge 3.6 files: Modules/mmapmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -383,8 +383,10 @@ if (!PyArg_ParseTuple(args, "y*:write", &data)) return(NULL); - if (!is_writable(self)) + if (!is_writable(self)) { + PyBuffer_Release(&data); return NULL; + } if (self->pos > self->size || self->size - self->pos < data.len) { PyBuffer_Release(&data); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:32:42 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:32:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_merge_3=2E5?= Message-ID: <20161006063242.79619.16170.7EEBE893@psf.io> https://hg.python.org/cpython/rev/20c637a0bff7 changeset: 104334:20c637a0bff7 branch: 3.6 parent: 104331:5f1badfc8a99 parent: 104333:ee3aeaea62ae user: Benjamin Peterson date: Wed Oct 05 23:32:15 2016 -0700 summary: merge 3.5 files: Modules/mmapmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -267,7 +267,7 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes, remaining; + Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; PyObject *result; CHECK_VALID(NULL); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:32:42 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:32:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_ensure_read_si?= =?utf-8?q?ze_is_initialized?= Message-ID: <20161006063242.20991.40341.24F994B2@psf.io> https://hg.python.org/cpython/rev/ee3aeaea62ae changeset: 104333:ee3aeaea62ae branch: 3.5 parent: 104330:dfb9088f7308 user: Benjamin Peterson date: Wed Oct 05 23:32:09 2016 -0700 summary: ensure read size is initialized files: Modules/mmapmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -267,7 +267,7 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes, remaining; + Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; PyObject *result; CHECK_VALID(NULL); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 02:32:42 2016 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Oct 2016 06:32:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161006063242.1397.9191.0689C752@psf.io> https://hg.python.org/cpython/rev/ed15bc7c4205 changeset: 104335:ed15bc7c4205 parent: 104332:854c89d61536 parent: 104334:20c637a0bff7 user: Benjamin Peterson date: Wed Oct 05 23:32:20 2016 -0700 summary: merge 3.6 files: Modules/mmapmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -267,7 +267,7 @@ mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes, remaining; + Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; PyObject *result; CHECK_VALID(NULL); -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Thu Oct 6 08:53:07 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 6 Oct 2016 13:53:07 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python 2.7 2016-10-06 Message-ID: No new revisions. Here are the previous results: Results for project Python 2.7, build date 2016-10-06 02:47:33 +0000 commit: 522adc2e082a previous commit: a0b9c4f98573 revision date: 2016-10-04 15:17:08 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% 1.61% 5.31% 3.23% :-) pybench 0.22% -0.08% 5.97% 4.19% :-( regex_v8 0.66% -0.03% -2.25% 11.13% :-) nbody 0.05% 0.21% 7.47% 6.85% :-) json_dump_v2 0.30% 1.10% 2.96% 9.77% :-| normal_startup 0.62% 0.03% -0.50% 2.61% :-| ssbench 0.19% -0.14% 2.00% 2.01% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-2-7-2016-10-06/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Thu Oct 6 08:54:22 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 6 Oct 2016 13:54:22 +0100 Subject: [Python-checkins] BAD Benchmark Results for Python Default 2016-10-06 Message-ID: <0c98d08a-31dd-4467-a789-295078587a4c@irsmsx102.ger.corp.intel.com> Results for project Python default, build date 2016-10-06 02:01:25 +0000 commit: f2204eaba685 previous commit: 71fd5d2447d4 revision date: 2016-10-05 23:40:40 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.18% 0.19% 5.31% 15.93% :-) pybench 0.08% -0.11% 5.47% 4.77% :-( regex_v8 3.38% -2.50% -6.34% 6.85% :-) nbody 0.13% 0.13% 3.84% 3.29% :-( json_dump_v2 0.33% -0.01% -12.59% 17.71% :-| normal_startup 0.89% 0.88% 0.66% 6.21% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/bad-benchmark-results-for-python-default-2016-10-06/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Thu Oct 6 10:51:44 2016 From: python-checkins at python.org (ned.deily) Date: Thu, 06 Oct 2016 14:51:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_vestigial_spelling=2E?= Message-ID: <20161006145144.20251.84779.819DE3AF@psf.io> https://hg.python.org/cpython/rev/cf3b202fac50 changeset: 104336:cf3b202fac50 user: Ned Deily date: Thu Oct 06 10:51:29 2016 -0400 summary: Fix vestigial spelling. 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 @@ -175,7 +175,7 @@ - Issue #27759: Fix selectors incorrectly retain invalid file descriptors. Patch by Mark Williams. -- Issue #28325: Remove vestigal MacOS 9 macurl2path module and its tests. +- Issue #28325: Remove vestigial MacOS 9 macurl2path module and its tests. - Issue #28368: Refuse monitoring processes if the child watcher has no loop attached. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 14:06:37 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 06 Oct 2016 18:06:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge_with_3=2E6?= Message-ID: <20161006180637.19983.78731.4DB5EA4C@psf.io> https://hg.python.org/cpython/rev/2788a5a435ec changeset: 104340:2788a5a435ec parent: 104336:cf3b202fac50 parent: 104339:b88be2133323 user: Yury Selivanov date: Thu Oct 06 14:06:20 2016 -0400 summary: Null merge with 3.6 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 14:06:36 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 06 Oct 2016 18:06:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI3NzU5?= =?utf-8?q?=3A_Fix_selectors_incorrectly_retain_invalid_file_descriptors?= =?utf-8?q?=2E?= Message-ID: <20161006180636.17616.3632.77F10043@psf.io> https://hg.python.org/cpython/rev/8cc1fca83fb8 changeset: 104337:8cc1fca83fb8 branch: 3.4 parent: 103949:ccfea26e6582 user: Yury Selivanov date: Thu Oct 06 14:03:03 2016 -0400 summary: Issue #27759: Fix selectors incorrectly retain invalid file descriptors. (Backported to 3.4 as this bug might be exploited to for DoS) files: Lib/selectors.py | 26 +++++++++++++++++--------- Lib/test/test_selectors.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -399,7 +399,11 @@ epoll_events |= select.EPOLLIN if events & EVENT_WRITE: epoll_events |= select.EPOLLOUT - self._epoll.register(key.fd, epoll_events) + try: + self._epoll.register(key.fd, epoll_events) + except BaseException: + super().unregister(fileobj) + raise return key def unregister(self, fileobj): @@ -465,14 +469,18 @@ def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) - if events & EVENT_READ: - kev = select.kevent(key.fd, select.KQ_FILTER_READ, - select.KQ_EV_ADD) - self._kqueue.control([kev], 0, 0) - if events & EVENT_WRITE: - kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, - select.KQ_EV_ADD) - self._kqueue.control([kev], 0, 0) + try: + if events & EVENT_READ: + kev = select.kevent(key.fd, select.KQ_FILTER_READ, + select.KQ_EV_ADD) + self._kqueue.control([kev], 0, 0) + if events & EVENT_WRITE: + kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, + select.KQ_EV_ADD) + self._kqueue.control([kev], 0, 0) + except BaseException: + super().unregister(fileobj) + raise return key def unregister(self, fileobj): diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -5,6 +5,7 @@ import signal import socket import sys +import tempfile from test import support from time import sleep import unittest @@ -447,6 +448,16 @@ SELECTOR = getattr(selectors, 'EpollSelector', None) + def test_register_file(self): + # epoll(7) returns EPERM when given a file to watch + s = self.SELECTOR() + with tempfile.NamedTemporaryFile() as f: + with self.assertRaises(IOError): + s.register(f, selectors.EVENT_READ) + # the SelectorKey has been removed + with self.assertRaises(KeyError): + s.get_key(f) + @unittest.skipUnless(hasattr(selectors, 'KqueueSelector'), "Test needs selectors.KqueueSelector)") @@ -454,6 +465,18 @@ SELECTOR = getattr(selectors, 'KqueueSelector', None) + def test_register_bad_fd(self): + # a file descriptor that's been closed should raise an OSError + # with EBADF + s = self.SELECTOR() + bad_f = support.make_bad_fd() + with self.assertRaises(OSError) as cm: + s.register(bad_f, selectors.EVENT_READ) + self.assertEqual(cm.exception.errno, errno.EBADF) + # the SelectorKey has been removed + with self.assertRaises(KeyError): + s.get_key(bad_f) + def test_main(): tests = [DefaultSelectorTestCase, SelectSelectorTestCase, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,9 @@ HTTP_PROXY variable when REQUEST_METHOD environment is set, which indicates that the script is in CGI mode. +- Issue #27759: Fix selectors incorrectly retain invalid file descriptors. + Patch by Mark Williams. + Tests ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 14:06:37 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 06 Oct 2016 18:06:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Null_merge_with_3=2E5?= Message-ID: <20161006180636.95073.91323.645688B9@psf.io> https://hg.python.org/cpython/rev/b88be2133323 changeset: 104339:b88be2133323 branch: 3.6 parent: 104334:20c637a0bff7 parent: 104338:b252c8079342 user: Yury Selivanov date: Thu Oct 06 14:05:42 2016 -0400 summary: Null merge with 3.5 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 14:06:37 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 06 Oct 2016 18:06:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Null_merge_with_3=2E4?= Message-ID: <20161006180636.82118.57882.D2B880A2@psf.io> https://hg.python.org/cpython/rev/b252c8079342 changeset: 104338:b252c8079342 branch: 3.5 parent: 104333:ee3aeaea62ae parent: 104337:8cc1fca83fb8 user: Yury Selivanov date: Thu Oct 06 14:05:17 2016 -0400 summary: Null merge with 3.4 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 17:32:27 2016 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 06 Oct 2016 21:32:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Fixes_issue283?= =?utf-8?q?80=3A_unittest=2Emock_Mock_autospec_functions_now_properly_supp?= =?utf-8?q?ort?= Message-ID: <20161006213227.79450.15465.F04FBEB5@psf.io> https://hg.python.org/cpython/rev/4e39b4e57673 changeset: 104341:4e39b4e57673 branch: 3.6 parent: 104339:b88be2133323 user: Gregory P. Smith date: Thu Oct 06 14:31:23 2016 -0700 summary: Fixes issue28380: unittest.mock Mock autospec functions now properly support assert_called, assert_not_called, and assert_called_once. files: Lib/unittest/mock.py | 9 +++++++++ Lib/unittest/test/testmock/testpatch.py | 6 ++++++ Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -193,6 +193,12 @@ def assert_called_with(*args, **kwargs): return mock.assert_called_with(*args, **kwargs) + def assert_called(*args, **kwargs): + return mock.assert_called(*args, **kwargs) + def assert_not_called(*args, **kwargs): + return mock.assert_not_called(*args, **kwargs) + def assert_called_once(*args, **kwargs): + return mock.assert_called_once(*args, **kwargs) def assert_called_once_with(*args, **kwargs): return mock.assert_called_once_with(*args, **kwargs) def assert_has_calls(*args, **kwargs): @@ -223,6 +229,9 @@ funcopy.assert_has_calls = assert_has_calls funcopy.assert_any_call = assert_any_call funcopy.reset_mock = reset_mock + funcopy.assert_called = assert_called + funcopy.assert_not_called = assert_not_called + funcopy.assert_called_once = assert_called_once mock._mock_delegate = funcopy diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -969,8 +969,14 @@ def test_autospec_function(self): @patch('%s.function' % __name__, autospec=True) def test(mock): + function.assert_not_called() + self.assertRaises(AssertionError, function.assert_called) + self.assertRaises(AssertionError, function.assert_called_once) function(1) + self.assertRaises(AssertionError, function.assert_not_called) function.assert_called_with(1) + function.assert_called() + function.assert_called_once() function(2, 3) function.assert_called_with(2, 3) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ Library ------- +- Issue #28380: unittest.mock Mock autospec functions now properly support + assert_called, assert_not_called, and assert_called_once. + - Issue #27181 remove statistics.geometric_mean and defer until 3.7. - Issue #28229: lzma module now supports pathlib. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 6 17:32:27 2016 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 06 Oct 2016 21:32:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328380=3A_unittest=2Emock_Mock_autospec_function?= =?utf-8?q?s_now_properly_support?= Message-ID: <20161006213227.85577.98034.E5F4B5FA@psf.io> https://hg.python.org/cpython/rev/fca5c4a63251 changeset: 104342:fca5c4a63251 parent: 104340:2788a5a435ec parent: 104341:4e39b4e57673 user: Gregory P. Smith date: Thu Oct 06 14:32:10 2016 -0700 summary: Issue #28380: unittest.mock Mock autospec functions now properly support assert_called, assert_not_called, and assert_called_once. files: Lib/unittest/mock.py | 9 +++++++++ Lib/unittest/test/testmock/testpatch.py | 6 ++++++ Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -193,6 +193,12 @@ def assert_called_with(*args, **kwargs): return mock.assert_called_with(*args, **kwargs) + def assert_called(*args, **kwargs): + return mock.assert_called(*args, **kwargs) + def assert_not_called(*args, **kwargs): + return mock.assert_not_called(*args, **kwargs) + def assert_called_once(*args, **kwargs): + return mock.assert_called_once(*args, **kwargs) def assert_called_once_with(*args, **kwargs): return mock.assert_called_once_with(*args, **kwargs) def assert_has_calls(*args, **kwargs): @@ -223,6 +229,9 @@ funcopy.assert_has_calls = assert_has_calls funcopy.assert_any_call = assert_any_call funcopy.reset_mock = reset_mock + funcopy.assert_called = assert_called + funcopy.assert_not_called = assert_not_called + funcopy.assert_called_once = assert_called_once mock._mock_delegate = funcopy diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -969,8 +969,14 @@ def test_autospec_function(self): @patch('%s.function' % __name__, autospec=True) def test(mock): + function.assert_not_called() + self.assertRaises(AssertionError, function.assert_called) + self.assertRaises(AssertionError, function.assert_called_once) function(1) + self.assertRaises(AssertionError, function.assert_not_called) function.assert_called_with(1) + function.assert_called() + function.assert_called_once() function(2, 3) function.assert_called_with(2, 3) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,9 @@ Library ------- +- Issue #28380: unittest.mock Mock autospec functions now properly support + assert_called, assert_not_called, and assert_called_once. + - Issue #28229: lzma module now supports pathlib. - Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Fri Oct 7 08:50:21 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 7 Oct 2016 13:50:21 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-07 Message-ID: <8c2b32b6-5c5c-48a3-a323-61cf5344d613@irsmsx103.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-07 02:47:27 +0000 commit: 59260b38f7cd previous commit: 522adc2e082a revision date: 2016-10-06 06:26:24 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.13% -0.76% 4.59% 3.60% :-) pybench 0.21% 0.13% 6.09% 3.00% :-( regex_v8 0.68% -0.06% -2.32% 10.90% :-) nbody 0.05% 0.03% 7.50% 3.21% :-) json_dump_v2 0.31% -0.03% 2.93% 10.64% :-| normal_startup 1.24% 0.81% 0.31% 1.33% :-) ssbench 0.36% 0.04% 2.04% 1.33% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-07/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Fri Oct 7 08:51:31 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 7 Oct 2016 13:51:31 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-07 Message-ID: <0bf5df87-36c1-4592-8a11-8792376af7c4@irsmsx103.ger.corp.intel.com> Results for project Python default, build date 2016-10-07 02:01:01 +0000 commit: fca5c4a63251 previous commit: f2204eaba685 revision date: 2016-10-06 21:32:10 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.14% 0.33% 5.62% 14.18% :-) pybench 0.11% -0.19% 5.29% 5.48% :-) regex_v8 3.79% 4.27% -1.80% 2.75% :-) nbody 0.30% -0.09% 3.76% 2.79% :-( json_dump_v2 0.31% -1.04% -13.76% 17.99% :-| normal_startup 0.57% -0.12% 1.61% 7.09% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-07/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Fri Oct 7 12:40:50 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 07 Oct 2016 16:40:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28asyncio=29?= Message-ID: <20161007164050.15793.90336.75766F29@psf.io> https://hg.python.org/cpython/rev/40c0c2eedf17 changeset: 104344:40c0c2eedf17 branch: 3.6 parent: 104341:4e39b4e57673 parent: 104343:1c5459c597ba user: Yury Selivanov date: Fri Oct 07 12:40:22 2016 -0400 summary: Merge 3.5 (asyncio) files: Lib/asyncio/unix_events.py | 11 +++++++++-- Lib/test/test_asyncio/test_unix_events.py | 11 ++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -234,6 +234,11 @@ else: if sock is None: raise ValueError('no path and sock were specified') + if (sock.family != socket.AF_UNIX or + sock.type != socket.SOCK_STREAM): + raise ValueError( + 'A UNIX Domain Stream Socket was expected, got {!r}' + .format(sock)) sock.setblocking(False) transport, protocol = yield from self._create_connection_transport( @@ -272,9 +277,11 @@ raise ValueError( 'path was not specified, and no sock specified') - if sock.family != socket.AF_UNIX: + if (sock.family != socket.AF_UNIX or + sock.type != socket.SOCK_STREAM): raise ValueError( - 'A UNIX Domain Socket was expected, got {!r}'.format(sock)) + 'A UNIX Domain Stream Socket was expected, got {!r}' + .format(sock)) server = base_events.Server(self, [sock]) sock.listen(backlog) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -273,7 +273,16 @@ coro = self.loop.create_unix_server(lambda: None, path=None, sock=sock) with self.assertRaisesRegex(ValueError, - 'A UNIX Domain Socket was expected'): + 'A UNIX Domain Stream.*was expected'): + self.loop.run_until_complete(coro) + + def test_create_unix_connection_path_inetsock(self): + sock = socket.socket() + with sock: + coro = self.loop.create_unix_connection(lambda: None, path=None, + sock=sock) + with self.assertRaisesRegex(ValueError, + 'A UNIX Domain Stream.*was expected'): self.loop.run_until_complete(coro) @mock.patch('asyncio.unix_events.socket') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 12:40:50 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 07 Oct 2016 16:40:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogYXN5bmNpbzogT25s?= =?utf-8?q?y_allow_Unix_Stream_sockets_for_loop=2Ecreate=5Funix=5Fserver/c?= =?utf-8?q?onnection?= Message-ID: <20161007164050.15637.21024.B9204641@psf.io> https://hg.python.org/cpython/rev/1c5459c597ba changeset: 104343:1c5459c597ba branch: 3.5 parent: 104338:b252c8079342 user: Yury Selivanov date: Fri Oct 07 12:39:57 2016 -0400 summary: asyncio: Only allow Unix Stream sockets for loop.create_unix_server/connection files: Lib/asyncio/unix_events.py | 11 +++++++++-- Lib/test/test_asyncio/test_unix_events.py | 11 ++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -234,6 +234,11 @@ else: if sock is None: raise ValueError('no path and sock were specified') + if (sock.family != socket.AF_UNIX or + sock.type != socket.SOCK_STREAM): + raise ValueError( + 'A UNIX Domain Stream Socket was expected, got {!r}' + .format(sock)) sock.setblocking(False) transport, protocol = yield from self._create_connection_transport( @@ -272,9 +277,11 @@ raise ValueError( 'path was not specified, and no sock specified') - if sock.family != socket.AF_UNIX: + if (sock.family != socket.AF_UNIX or + sock.type != socket.SOCK_STREAM): raise ValueError( - 'A UNIX Domain Socket was expected, got {!r}'.format(sock)) + 'A UNIX Domain Stream Socket was expected, got {!r}' + .format(sock)) server = base_events.Server(self, [sock]) sock.listen(backlog) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -273,7 +273,16 @@ coro = self.loop.create_unix_server(lambda: None, path=None, sock=sock) with self.assertRaisesRegex(ValueError, - 'A UNIX Domain Socket was expected'): + 'A UNIX Domain Stream.*was expected'): + self.loop.run_until_complete(coro) + + def test_create_unix_connection_path_inetsock(self): + sock = socket.socket() + with sock: + coro = self.loop.create_unix_connection(lambda: None, path=None, + sock=sock) + with self.assertRaisesRegex(ValueError, + 'A UNIX Domain Stream.*was expected'): self.loop.run_until_complete(coro) @mock.patch('asyncio.unix_events.socket') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 12:40:51 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 07 Oct 2016 16:40:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E6_=28asyncio=29?= Message-ID: <20161007164050.79384.52368.4FF6A029@psf.io> https://hg.python.org/cpython/rev/8ed6c53c3432 changeset: 104345:8ed6c53c3432 parent: 104342:fca5c4a63251 parent: 104344:40c0c2eedf17 user: Yury Selivanov date: Fri Oct 07 12:40:44 2016 -0400 summary: Merge 3.6 (asyncio) files: Lib/asyncio/unix_events.py | 11 +++++++++-- Lib/test/test_asyncio/test_unix_events.py | 11 ++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -234,6 +234,11 @@ else: if sock is None: raise ValueError('no path and sock were specified') + if (sock.family != socket.AF_UNIX or + sock.type != socket.SOCK_STREAM): + raise ValueError( + 'A UNIX Domain Stream Socket was expected, got {!r}' + .format(sock)) sock.setblocking(False) transport, protocol = yield from self._create_connection_transport( @@ -272,9 +277,11 @@ raise ValueError( 'path was not specified, and no sock specified') - if sock.family != socket.AF_UNIX: + if (sock.family != socket.AF_UNIX or + sock.type != socket.SOCK_STREAM): raise ValueError( - 'A UNIX Domain Socket was expected, got {!r}'.format(sock)) + 'A UNIX Domain Stream Socket was expected, got {!r}' + .format(sock)) server = base_events.Server(self, [sock]) sock.listen(backlog) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -273,7 +273,16 @@ coro = self.loop.create_unix_server(lambda: None, path=None, sock=sock) with self.assertRaisesRegex(ValueError, - 'A UNIX Domain Socket was expected'): + 'A UNIX Domain Stream.*was expected'): + self.loop.run_until_complete(coro) + + def test_create_unix_connection_path_inetsock(self): + sock = socket.socket() + with sock: + coro = self.loop.create_unix_connection(lambda: None, path=None, + sock=sock) + with self.assertRaisesRegex(ValueError, + 'A UNIX Domain Stream.*was expected'): self.loop.run_until_complete(coro) @mock.patch('asyncio.unix_events.socket') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 14:57:45 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 18:57:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0MDk4?= =?utf-8?q?=3A_Fixed_possible_crash_when_AST_is_changed_in_process_of?= Message-ID: <20161007185745.15320.98349.94663D7D@psf.io> https://hg.python.org/cpython/rev/f575710b5f56 changeset: 104347:f575710b5f56 branch: 3.5 parent: 104343:1c5459c597ba user: Serhiy Storchaka date: Fri Oct 07 21:51:28 2016 +0300 summary: Issue #24098: Fixed possible crash when AST is changed in process of compiling it. files: Misc/NEWS | 3 + Parser/asdl_c.py | 7 + Python/Python-ast.c | 216 ++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #24098: Fixed possible crash when AST is changed in process of + compiling it. + - Issue #28350: String constants with null character no longer interned. - Issue #26617: Fix crash when GC runs during weakref callbacks. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -526,6 +526,13 @@ self.emit("res = obj2ast_%s(PyList_GET_ITEM(tmp, i), &value, arena);" % field.type, depth+2, reflow=False) self.emit("if (res != 0) goto failed;", depth+2) + self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2) + self.emit("PyErr_SetString(PyExc_RuntimeError, \"%s field \\\"%s\\\" " + "changed size during iteration\");" % + (name, field.name), + depth+3, reflow=False) + self.emit("goto failed;", depth+3) + self.emit("}", depth+2) self.emit("asdl_seq_SET(%s, i, value);" % field.name, depth+2) self.emit("}", depth+1) else: diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -3797,6 +3797,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -3832,6 +3836,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -3889,6 +3897,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Suite field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -3992,6 +4004,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4016,6 +4032,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4088,6 +4108,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4112,6 +4136,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4173,6 +4201,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration"); + goto failed; + } asdl_seq_SET(bases, i, value); } Py_CLEAR(tmp); @@ -4197,6 +4229,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_CLEAR(tmp); @@ -4221,6 +4257,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4245,6 +4285,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4302,6 +4346,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_CLEAR(tmp); @@ -4338,6 +4386,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_CLEAR(tmp); @@ -4455,6 +4507,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4479,6 +4535,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4539,6 +4599,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4563,6 +4627,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4611,6 +4679,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4635,6 +4707,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4683,6 +4759,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4707,6 +4787,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4743,6 +4827,10 @@ withitem_ty value; res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"items\" changed size during iteration"); + goto failed; + } asdl_seq_SET(items, i, value); } Py_CLEAR(tmp); @@ -4767,6 +4855,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4803,6 +4895,10 @@ withitem_ty value; res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"items\" changed size during iteration"); + goto failed; + } asdl_seq_SET(items, i, value); } Py_CLEAR(tmp); @@ -4827,6 +4923,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4897,6 +4997,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4921,6 +5025,10 @@ excepthandler_ty value; res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"handlers\" changed size during iteration"); + goto failed; + } asdl_seq_SET(handlers, i, value); } Py_CLEAR(tmp); @@ -4945,6 +5053,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4969,6 +5081,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"finalbody\" changed size during iteration"); + goto failed; + } asdl_seq_SET(finalbody, i, value); } Py_CLEAR(tmp); @@ -5038,6 +5154,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5085,6 +5205,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5130,6 +5254,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5165,6 +5293,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Nonlocal field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5306,6 +5438,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -5502,6 +5638,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keys, i, value); } Py_CLEAR(tmp); @@ -5526,6 +5666,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -5561,6 +5705,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -5608,6 +5756,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5655,6 +5807,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5714,6 +5870,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5761,6 +5921,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5874,6 +6038,10 @@ cmpop_ty value; res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ops, i, value); } Py_CLEAR(tmp); @@ -5898,6 +6066,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(comparators, i, value); } Py_CLEAR(tmp); @@ -5946,6 +6118,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_CLEAR(tmp); @@ -5970,6 +6146,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_CLEAR(tmp); @@ -6264,6 +6444,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -6311,6 +6495,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -6476,6 +6664,10 @@ slice_ty value; res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExtSlice field \"dims\" changed size during iteration"); + goto failed; + } asdl_seq_SET(dims, i, value); } Py_CLEAR(tmp); @@ -6835,6 +7027,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ifs, i, value); } Py_CLEAR(tmp); @@ -6930,6 +7126,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -6976,6 +7176,10 @@ arg_ty value; res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_CLEAR(tmp); @@ -7010,6 +7214,10 @@ arg_ty value; res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"kwonlyargs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(kwonlyargs, i, value); } Py_CLEAR(tmp); @@ -7034,6 +7242,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"kw_defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(kw_defaults, i, value); } Py_CLEAR(tmp); @@ -7068,6 +7280,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(defaults, i, value); } Py_CLEAR(tmp); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 14:57:45 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 18:57:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324098=3A_Fixed_possible_crash_when_AST_is_chang?= =?utf-8?q?ed_in_process_of?= Message-ID: <20161007185745.15249.2137.978532E4@psf.io> https://hg.python.org/cpython/rev/def217aaad2f changeset: 104349:def217aaad2f parent: 104345:8ed6c53c3432 parent: 104348:7528154cadaa user: Serhiy Storchaka date: Fri Oct 07 21:56:24 2016 +0300 summary: Issue #24098: Fixed possible crash when AST is changed in process of compiling it. files: Misc/NEWS | 3 + Parser/asdl_c.py | 7 + Python/Python-ast.c | 220 ++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #24098: Fixed possible crash when AST is changed in process of + compiling it. + - Issue #28201: Dict reduces possibility of 2nd conflict in hash table when hashes have same lower bits. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -526,6 +526,13 @@ self.emit("res = obj2ast_%s(PyList_GET_ITEM(tmp, i), &value, arena);" % field.type, depth+2, reflow=False) self.emit("if (res != 0) goto failed;", depth+2) + self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2) + self.emit("PyErr_SetString(PyExc_RuntimeError, \"%s field \\\"%s\\\" " + "changed size during iteration\");" % + (name, field.name), + depth+3, reflow=False) + self.emit("goto failed;", depth+3) + self.emit("}", depth+2) self.emit("asdl_seq_SET(%s, i, value);" % field.name, depth+2) self.emit("}", depth+1) else: diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -3997,6 +3997,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4032,6 +4036,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4089,6 +4097,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Suite field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4192,6 +4204,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4216,6 +4232,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4288,6 +4308,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4312,6 +4336,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4373,6 +4401,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration"); + goto failed; + } asdl_seq_SET(bases, i, value); } Py_CLEAR(tmp); @@ -4397,6 +4429,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_CLEAR(tmp); @@ -4421,6 +4457,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4445,6 +4485,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4502,6 +4546,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_CLEAR(tmp); @@ -4538,6 +4586,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_CLEAR(tmp); @@ -4713,6 +4765,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4737,6 +4793,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4797,6 +4857,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4821,6 +4885,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4869,6 +4937,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4893,6 +4965,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4941,6 +5017,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4965,6 +5045,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -5001,6 +5085,10 @@ withitem_ty value; res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"items\" changed size during iteration"); + goto failed; + } asdl_seq_SET(items, i, value); } Py_CLEAR(tmp); @@ -5025,6 +5113,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -5061,6 +5153,10 @@ withitem_ty value; res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"items\" changed size during iteration"); + goto failed; + } asdl_seq_SET(items, i, value); } Py_CLEAR(tmp); @@ -5085,6 +5181,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -5155,6 +5255,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -5179,6 +5283,10 @@ excepthandler_ty value; res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"handlers\" changed size during iteration"); + goto failed; + } asdl_seq_SET(handlers, i, value); } Py_CLEAR(tmp); @@ -5203,6 +5311,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -5227,6 +5339,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"finalbody\" changed size during iteration"); + goto failed; + } asdl_seq_SET(finalbody, i, value); } Py_CLEAR(tmp); @@ -5296,6 +5412,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5343,6 +5463,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5388,6 +5512,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5423,6 +5551,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Nonlocal field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5564,6 +5696,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -5760,6 +5896,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keys, i, value); } Py_CLEAR(tmp); @@ -5784,6 +5924,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -5819,6 +5963,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -5866,6 +6014,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5913,6 +6065,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5972,6 +6128,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -6019,6 +6179,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -6132,6 +6296,10 @@ cmpop_ty value; res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ops, i, value); } Py_CLEAR(tmp); @@ -6156,6 +6324,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(comparators, i, value); } Py_CLEAR(tmp); @@ -6204,6 +6376,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_CLEAR(tmp); @@ -6228,6 +6404,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_CLEAR(tmp); @@ -6352,6 +6532,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "JoinedStr field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -6624,6 +6808,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -6671,6 +6859,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -6836,6 +7028,10 @@ slice_ty value; res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExtSlice field \"dims\" changed size during iteration"); + goto failed; + } asdl_seq_SET(dims, i, value); } Py_CLEAR(tmp); @@ -7196,6 +7392,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ifs, i, value); } Py_CLEAR(tmp); @@ -7302,6 +7502,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -7348,6 +7552,10 @@ arg_ty value; res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_CLEAR(tmp); @@ -7382,6 +7590,10 @@ arg_ty value; res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"kwonlyargs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(kwonlyargs, i, value); } Py_CLEAR(tmp); @@ -7406,6 +7618,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"kw_defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(kw_defaults, i, value); } Py_CLEAR(tmp); @@ -7440,6 +7656,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(defaults, i, value); } Py_CLEAR(tmp); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 14:57:45 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 18:57:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2324098=3A_Fixed_possible_crash_when_AST_is_changed_in_?= =?utf-8?q?process_of?= Message-ID: <20161007185745.17468.34470.47646473@psf.io> https://hg.python.org/cpython/rev/7528154cadaa changeset: 104348:7528154cadaa branch: 3.6 parent: 104344:40c0c2eedf17 parent: 104347:f575710b5f56 user: Serhiy Storchaka date: Fri Oct 07 21:55:49 2016 +0300 summary: Issue #24098: Fixed possible crash when AST is changed in process of compiling it. files: Misc/NEWS | 3 + Parser/asdl_c.py | 7 + Python/Python-ast.c | 220 ++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #24098: Fixed possible crash when AST is changed in process of + compiling it. + - Issue #28201: Dict reduces possibility of 2nd conflict in hash table when hashes have same lower bits. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -526,6 +526,13 @@ self.emit("res = obj2ast_%s(PyList_GET_ITEM(tmp, i), &value, arena);" % field.type, depth+2, reflow=False) self.emit("if (res != 0) goto failed;", depth+2) + self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2) + self.emit("PyErr_SetString(PyExc_RuntimeError, \"%s field \\\"%s\\\" " + "changed size during iteration\");" % + (name, field.name), + depth+3, reflow=False) + self.emit("goto failed;", depth+3) + self.emit("}", depth+2) self.emit("asdl_seq_SET(%s, i, value);" % field.name, depth+2) self.emit("}", depth+1) else: diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -3997,6 +3997,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4032,6 +4036,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4089,6 +4097,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Suite field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4192,6 +4204,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4216,6 +4232,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4288,6 +4308,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4312,6 +4336,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4373,6 +4401,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration"); + goto failed; + } asdl_seq_SET(bases, i, value); } Py_CLEAR(tmp); @@ -4397,6 +4429,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_CLEAR(tmp); @@ -4421,6 +4457,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4445,6 +4485,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_CLEAR(tmp); @@ -4502,6 +4546,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_CLEAR(tmp); @@ -4538,6 +4586,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_CLEAR(tmp); @@ -4713,6 +4765,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4737,6 +4793,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4797,6 +4857,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4821,6 +4885,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4869,6 +4937,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4893,6 +4965,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -4941,6 +5017,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -4965,6 +5045,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -5001,6 +5085,10 @@ withitem_ty value; res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"items\" changed size during iteration"); + goto failed; + } asdl_seq_SET(items, i, value); } Py_CLEAR(tmp); @@ -5025,6 +5113,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -5061,6 +5153,10 @@ withitem_ty value; res = obj2ast_withitem(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"items\" changed size during iteration"); + goto failed; + } asdl_seq_SET(items, i, value); } Py_CLEAR(tmp); @@ -5085,6 +5181,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -5155,6 +5255,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -5179,6 +5283,10 @@ excepthandler_ty value; res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"handlers\" changed size during iteration"); + goto failed; + } asdl_seq_SET(handlers, i, value); } Py_CLEAR(tmp); @@ -5203,6 +5311,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_CLEAR(tmp); @@ -5227,6 +5339,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Try field \"finalbody\" changed size during iteration"); + goto failed; + } asdl_seq_SET(finalbody, i, value); } Py_CLEAR(tmp); @@ -5296,6 +5412,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5343,6 +5463,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5388,6 +5512,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5423,6 +5551,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Nonlocal field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_CLEAR(tmp); @@ -5564,6 +5696,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -5760,6 +5896,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keys, i, value); } Py_CLEAR(tmp); @@ -5784,6 +5924,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -5819,6 +5963,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -5866,6 +6014,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5913,6 +6065,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -5972,6 +6128,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -6019,6 +6179,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_CLEAR(tmp); @@ -6132,6 +6296,10 @@ cmpop_ty value; res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ops, i, value); } Py_CLEAR(tmp); @@ -6156,6 +6324,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(comparators, i, value); } Py_CLEAR(tmp); @@ -6204,6 +6376,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_CLEAR(tmp); @@ -6228,6 +6404,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_CLEAR(tmp); @@ -6352,6 +6532,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "JoinedStr field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_CLEAR(tmp); @@ -6624,6 +6808,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -6671,6 +6859,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_CLEAR(tmp); @@ -6836,6 +7028,10 @@ slice_ty value; res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExtSlice field \"dims\" changed size during iteration"); + goto failed; + } asdl_seq_SET(dims, i, value); } Py_CLEAR(tmp); @@ -7196,6 +7392,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ifs, i, value); } Py_CLEAR(tmp); @@ -7302,6 +7502,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_CLEAR(tmp); @@ -7348,6 +7552,10 @@ arg_ty value; res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_CLEAR(tmp); @@ -7382,6 +7590,10 @@ arg_ty value; res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"kwonlyargs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(kwonlyargs, i, value); } Py_CLEAR(tmp); @@ -7406,6 +7618,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"kw_defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(kw_defaults, i, value); } Py_CLEAR(tmp); @@ -7440,6 +7656,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(defaults, i, value); } Py_CLEAR(tmp); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 14:57:45 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 18:57:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0MDk4?= =?utf-8?q?=3A_Fixed_possible_crash_when_AST_is_changed_in_process_of?= Message-ID: <20161007185744.5092.69433.1A68D495@psf.io> https://hg.python.org/cpython/rev/47d5bf5a846f changeset: 104346:47d5bf5a846f branch: 2.7 parent: 104329:59260b38f7cd user: Serhiy Storchaka date: Fri Oct 07 21:51:09 2016 +0300 summary: Issue #24098: Fixed possible crash when AST is changed in process of compiling it. files: Misc/NEWS | 3 + Parser/asdl_c.py | 7 + Python/Python-ast.c | 180 ++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #24098: Fixed possible crash when AST is changed in process of + compiling it. + - Issue #28350: String constants with null character no longer interned. - Issue #27942: String constants now interned recursively in tuples and frozensets. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -513,6 +513,13 @@ self.emit("res = obj2ast_%s(PyList_GET_ITEM(tmp, i), &value, arena);" % field.type, depth+2, reflow=False) self.emit("if (res != 0) goto failed;", depth+2) + self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2) + self.emit("PyErr_SetString(PyExc_RuntimeError, \"%s field \\\"%s\\\" " + "changed size during iteration\");" % + (name, field.name), + depth+3, reflow=False) + self.emit("goto failed;", depth+3) + self.emit("}", depth+2) self.emit("asdl_seq_SET(%s, i, value);" % field.name, depth+2) self.emit("}", depth+1) else: diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -3351,6 +3351,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -3387,6 +3391,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -3446,6 +3454,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Suite field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -3555,6 +3567,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -3580,6 +3596,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_XDECREF(tmp); @@ -3632,6 +3652,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration"); + goto failed; + } asdl_seq_SET(bases, i, value); } Py_XDECREF(tmp); @@ -3657,6 +3681,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -3682,6 +3710,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration"); + goto failed; + } asdl_seq_SET(decorator_list, i, value); } Py_XDECREF(tmp); @@ -3741,6 +3773,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_XDECREF(tmp); @@ -3778,6 +3814,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration"); + goto failed; + } asdl_seq_SET(targets, i, value); } Py_XDECREF(tmp); @@ -3888,6 +3928,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Print field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_XDECREF(tmp); @@ -3963,6 +4007,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -3988,6 +4036,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_XDECREF(tmp); @@ -4039,6 +4091,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -4064,6 +4120,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_XDECREF(tmp); @@ -4114,6 +4174,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -4139,6 +4203,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_XDECREF(tmp); @@ -4200,6 +4268,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -4285,6 +4357,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "TryExcept field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -4310,6 +4386,10 @@ excepthandler_ty value; res = obj2ast_excepthandler(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "TryExcept field \"handlers\" changed size during iteration"); + goto failed; + } asdl_seq_SET(handlers, i, value); } Py_XDECREF(tmp); @@ -4335,6 +4415,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "TryExcept field \"orelse\" changed size during iteration"); + goto failed; + } asdl_seq_SET(orelse, i, value); } Py_XDECREF(tmp); @@ -4373,6 +4457,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "TryFinally field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -4398,6 +4486,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "TryFinally field \"finalbody\" changed size during iteration"); + goto failed; + } asdl_seq_SET(finalbody, i, value); } Py_XDECREF(tmp); @@ -4469,6 +4561,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_XDECREF(tmp); @@ -4518,6 +4614,10 @@ alias_ty value; res = obj2ast_alias(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_XDECREF(tmp); @@ -4613,6 +4713,10 @@ identifier value; res = obj2ast_identifier(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration"); + goto failed; + } asdl_seq_SET(names, i, value); } Py_XDECREF(tmp); @@ -4761,6 +4865,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_XDECREF(tmp); @@ -4968,6 +5076,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keys, i, value); } Py_XDECREF(tmp); @@ -4993,6 +5105,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration"); + goto failed; + } asdl_seq_SET(values, i, value); } Py_XDECREF(tmp); @@ -5029,6 +5145,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_XDECREF(tmp); @@ -5078,6 +5198,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_XDECREF(tmp); @@ -5127,6 +5251,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_XDECREF(tmp); @@ -5189,6 +5317,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_XDECREF(tmp); @@ -5239,6 +5371,10 @@ comprehension_ty value; res = obj2ast_comprehension(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(generators, i, value); } Py_XDECREF(tmp); @@ -5311,6 +5447,10 @@ cmpop_ty value; res = obj2ast_cmpop(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ops, i, value); } Py_XDECREF(tmp); @@ -5336,6 +5476,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration"); + goto failed; + } asdl_seq_SET(comparators, i, value); } Py_XDECREF(tmp); @@ -5389,6 +5533,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_XDECREF(tmp); @@ -5414,6 +5562,10 @@ keyword_ty value; res = obj2ast_keyword(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration"); + goto failed; + } asdl_seq_SET(keywords, i, value); } Py_XDECREF(tmp); @@ -5677,6 +5829,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_XDECREF(tmp); @@ -5726,6 +5882,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration"); + goto failed; + } asdl_seq_SET(elts, i, value); } Py_XDECREF(tmp); @@ -5913,6 +6073,10 @@ slice_ty value; res = obj2ast_slice(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExtSlice field \"dims\" changed size during iteration"); + goto failed; + } asdl_seq_SET(dims, i, value); } Py_XDECREF(tmp); @@ -6290,6 +6454,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration"); + goto failed; + } asdl_seq_SET(ifs, i, value); } Py_XDECREF(tmp); @@ -6390,6 +6558,10 @@ stmt_ty value; res = obj2ast_stmt(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration"); + goto failed; + } asdl_seq_SET(body, i, value); } Py_XDECREF(tmp); @@ -6438,6 +6610,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration"); + goto failed; + } asdl_seq_SET(args, i, value); } Py_XDECREF(tmp); @@ -6485,6 +6661,10 @@ expr_ty value; res = obj2ast_expr(PyList_GET_ITEM(tmp, i), &value, arena); if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration"); + goto failed; + } asdl_seq_SET(defaults, i, value); } Py_XDECREF(tmp); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 15:25:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 19:25:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326293=3A_Fixed_writing_ZIP_files_that_starts_no?= =?utf-8?q?t_from_the_start_of_the?= Message-ID: <20161007192522.1397.79536.71D3D168@psf.io> https://hg.python.org/cpython/rev/64a19fe3a16a changeset: 104352:64a19fe3a16a parent: 104349:def217aaad2f parent: 104351:b06e75ae1981 user: Serhiy Storchaka date: Fri Oct 07 22:25:05 2016 +0300 summary: Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. files: Lib/test/test_zipfile.py | 43 ++++++++++++++++++++++++++++ Lib/zipfile.py | 30 +++++++++--------- Misc/NEWS | 4 ++ 3 files changed, 62 insertions(+), 15 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 @@ -420,6 +420,49 @@ f.seek(len(data)) with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_read_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*10 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_append_to_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*1000000 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2, 'a') as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + zipfp.writestr('strfile', self.data) + + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile']) + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read('strfile'), self.data) def test_ignores_newline_at_end(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1103,10 +1103,10 @@ # even if no files are added to the archive self._didModify = True try: - self.start_dir = self.fp.tell() + self.start_dir = self._start_disk = self.fp.tell() except (AttributeError, OSError): self.fp = _Tellable(self.fp) - self.start_dir = 0 + self.start_dir = self._start_disk = 0 self._seekable = False else: # Some file-like objects can provide tell() but not seek() @@ -1127,7 +1127,7 @@ # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True - self.start_dir = self.fp.tell() + self.start_dir = self._start_disk = self.fp.tell() else: raise ValueError("Mode must be 'r', 'w', 'x', or 'a'") except: @@ -1171,17 +1171,18 @@ offset_cd = endrec[_ECD_OFFSET] # offset of central directory self._comment = endrec[_ECD_COMMENT] # archive comment - # "concat" is zero, unless zip was concatenated to another file - concat = endrec[_ECD_LOCATION] - size_cd - offset_cd + # self._start_disk: Position of the start of ZIP archive + # It is zero, unless ZIP was concatenated to another file + self._start_disk = endrec[_ECD_LOCATION] - size_cd - offset_cd if endrec[_ECD_SIGNATURE] == stringEndArchive64: # If Zip64 extension structures are present, account for them - concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator) + self._start_disk -= (sizeEndCentDir64 + sizeEndCentDir64Locator) if self.debug > 2: - inferred = concat + offset_cd - print("given, inferred, offset", offset_cd, inferred, concat) + inferred = self._start_disk + offset_cd + print("given, inferred, offset", offset_cd, inferred, self._start_disk) # self.start_dir: Position of start of central directory - self.start_dir = offset_cd + concat + self.start_dir = offset_cd + self._start_disk fp.seek(self.start_dir, 0) data = fp.read(size_cd) fp = io.BytesIO(data) @@ -1221,7 +1222,7 @@ t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) x._decodeExtra() - x.header_offset = x.header_offset + concat + x.header_offset = x.header_offset + self._start_disk self.filelist.append(x) self.NameToInfo[x.filename] = x @@ -1685,11 +1686,10 @@ file_size = zinfo.file_size compress_size = zinfo.compress_size - if zinfo.header_offset > ZIP64_LIMIT: - extra.append(zinfo.header_offset) + header_offset = zinfo.header_offset - self._start_disk + if header_offset > ZIP64_LIMIT: + extra.append(header_offset) header_offset = 0xffffffff - else: - header_offset = zinfo.header_offset extra_data = zinfo.extra min_version = 0 @@ -1736,7 +1736,7 @@ # Write end-of-zip-archive record centDirCount = len(self.filelist) centDirSize = pos2 - self.start_dir - centDirOffset = self.start_dir + centDirOffset = self.start_dir - self._start_disk requires_zip64 = None if centDirCount > ZIP_FILECOUNT_LIMIT: requires_zip64 = "Files count" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -64,6 +64,10 @@ Library ------- +- Issue #26293: Fixed writing ZIP files that starts not from the start of the + file. Offsets in ZIP file now are relative to the start of the archive in + conforming to the specification. + - Issue #28380: unittest.mock Mock autospec functions now properly support assert_called, assert_not_called, and assert_called_once. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 15:25:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 19:25:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2326293=3A_Fixed_writing_ZIP_files_that_starts_not_from?= =?utf-8?q?_the_start_of_the?= Message-ID: <20161007192522.85797.20038.970601D6@psf.io> https://hg.python.org/cpython/rev/b06e75ae1981 changeset: 104351:b06e75ae1981 branch: 3.6 parent: 104348:7528154cadaa parent: 104350:005704f5634f user: Serhiy Storchaka date: Fri Oct 07 22:24:20 2016 +0300 summary: Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. files: Lib/test/test_zipfile.py | 43 ++++++++++++++++++++++++++++ Lib/zipfile.py | 30 +++++++++--------- Misc/NEWS | 4 ++ 3 files changed, 62 insertions(+), 15 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 @@ -420,6 +420,49 @@ f.seek(len(data)) with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_read_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*10 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_append_to_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*1000000 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2, 'a') as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + zipfp.writestr('strfile', self.data) + + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile']) + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read('strfile'), self.data) def test_ignores_newline_at_end(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1103,10 +1103,10 @@ # even if no files are added to the archive self._didModify = True try: - self.start_dir = self.fp.tell() + self.start_dir = self._start_disk = self.fp.tell() except (AttributeError, OSError): self.fp = _Tellable(self.fp) - self.start_dir = 0 + self.start_dir = self._start_disk = 0 self._seekable = False else: # Some file-like objects can provide tell() but not seek() @@ -1127,7 +1127,7 @@ # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True - self.start_dir = self.fp.tell() + self.start_dir = self._start_disk = self.fp.tell() else: raise ValueError("Mode must be 'r', 'w', 'x', or 'a'") except: @@ -1171,17 +1171,18 @@ offset_cd = endrec[_ECD_OFFSET] # offset of central directory self._comment = endrec[_ECD_COMMENT] # archive comment - # "concat" is zero, unless zip was concatenated to another file - concat = endrec[_ECD_LOCATION] - size_cd - offset_cd + # self._start_disk: Position of the start of ZIP archive + # It is zero, unless ZIP was concatenated to another file + self._start_disk = endrec[_ECD_LOCATION] - size_cd - offset_cd if endrec[_ECD_SIGNATURE] == stringEndArchive64: # If Zip64 extension structures are present, account for them - concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator) + self._start_disk -= (sizeEndCentDir64 + sizeEndCentDir64Locator) if self.debug > 2: - inferred = concat + offset_cd - print("given, inferred, offset", offset_cd, inferred, concat) + inferred = self._start_disk + offset_cd + print("given, inferred, offset", offset_cd, inferred, self._start_disk) # self.start_dir: Position of start of central directory - self.start_dir = offset_cd + concat + self.start_dir = offset_cd + self._start_disk fp.seek(self.start_dir, 0) data = fp.read(size_cd) fp = io.BytesIO(data) @@ -1221,7 +1222,7 @@ t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) x._decodeExtra() - x.header_offset = x.header_offset + concat + x.header_offset = x.header_offset + self._start_disk self.filelist.append(x) self.NameToInfo[x.filename] = x @@ -1685,11 +1686,10 @@ file_size = zinfo.file_size compress_size = zinfo.compress_size - if zinfo.header_offset > ZIP64_LIMIT: - extra.append(zinfo.header_offset) + header_offset = zinfo.header_offset - self._start_disk + if header_offset > ZIP64_LIMIT: + extra.append(header_offset) header_offset = 0xffffffff - else: - header_offset = zinfo.header_offset extra_data = zinfo.extra min_version = 0 @@ -1736,7 +1736,7 @@ # Write end-of-zip-archive record centDirCount = len(self.filelist) centDirSize = pos2 - self.start_dir - centDirOffset = self.start_dir + centDirOffset = self.start_dir - self._start_disk requires_zip64 = None if centDirCount > ZIP_FILECOUNT_LIMIT: requires_zip64 = "Files count" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,10 @@ Library ------- +- Issue #26293: Fixed writing ZIP files that starts not from the start of the + file. Offsets in ZIP file now are relative to the start of the archive in + conforming to the specification. + - Issue #28380: unittest.mock Mock autospec functions now properly support assert_called, assert_not_called, and assert_called_once. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 15:25:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 19:25:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2Mjkz?= =?utf-8?q?=3A_Fixed_writing_ZIP_files_that_starts_not_from_the_start_of_t?= =?utf-8?q?he?= Message-ID: <20161007192521.76162.34797.8E639C7F@psf.io> https://hg.python.org/cpython/rev/005704f5634f changeset: 104350:005704f5634f branch: 3.5 parent: 104347:f575710b5f56 user: Serhiy Storchaka date: Fri Oct 07 22:20:50 2016 +0300 summary: Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. files: Lib/test/test_zipfile.py | 43 ++++++++++++++++++++++++++++ Lib/zipfile.py | 30 +++++++++--------- Misc/NEWS | 4 ++ 3 files changed, 62 insertions(+), 15 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 @@ -415,6 +415,49 @@ f.seek(len(data)) with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_read_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*10 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_append_to_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*1000000 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2, 'a') as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + zipfp.writestr('strfile', self.data) + + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile']) + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read('strfile'), self.data) def test_ignores_newline_at_end(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1029,10 +1029,10 @@ # even if no files are added to the archive self._didModify = True try: - self.start_dir = self.fp.tell() + self.start_dir = self._start_disk = self.fp.tell() except (AttributeError, OSError): self.fp = _Tellable(self.fp) - self.start_dir = 0 + self.start_dir = self._start_disk = 0 self._seekable = False else: # Some file-like objects can provide tell() but not seek() @@ -1053,7 +1053,7 @@ # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True - self.start_dir = self.fp.tell() + self.start_dir = self._start_disk = self.fp.tell() else: raise RuntimeError("Mode must be 'r', 'w', 'x', or 'a'") except: @@ -1097,17 +1097,18 @@ offset_cd = endrec[_ECD_OFFSET] # offset of central directory self._comment = endrec[_ECD_COMMENT] # archive comment - # "concat" is zero, unless zip was concatenated to another file - concat = endrec[_ECD_LOCATION] - size_cd - offset_cd + # self._start_disk: Position of the start of ZIP archive + # It is zero, unless ZIP was concatenated to another file + self._start_disk = endrec[_ECD_LOCATION] - size_cd - offset_cd if endrec[_ECD_SIGNATURE] == stringEndArchive64: # If Zip64 extension structures are present, account for them - concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator) + self._start_disk -= (sizeEndCentDir64 + sizeEndCentDir64Locator) if self.debug > 2: - inferred = concat + offset_cd - print("given, inferred, offset", offset_cd, inferred, concat) + inferred = self._start_disk + offset_cd + print("given, inferred, offset", offset_cd, inferred, self._start_disk) # self.start_dir: Position of start of central directory - self.start_dir = offset_cd + concat + self.start_dir = offset_cd + self._start_disk fp.seek(self.start_dir, 0) data = fp.read(size_cd) fp = io.BytesIO(data) @@ -1147,7 +1148,7 @@ t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) x._decodeExtra() - x.header_offset = x.header_offset + concat + x.header_offset = x.header_offset + self._start_disk self.filelist.append(x) self.NameToInfo[x.filename] = x @@ -1627,11 +1628,10 @@ file_size = zinfo.file_size compress_size = zinfo.compress_size - if zinfo.header_offset > ZIP64_LIMIT: - extra.append(zinfo.header_offset) + header_offset = zinfo.header_offset - self._start_disk + if header_offset > ZIP64_LIMIT: + extra.append(header_offset) header_offset = 0xffffffff - else: - header_offset = zinfo.header_offset extra_data = zinfo.extra min_version = 0 @@ -1678,7 +1678,7 @@ # Write end-of-zip-archive record centDirCount = len(self.filelist) centDirSize = pos2 - self.start_dir - centDirOffset = self.start_dir + centDirOffset = self.start_dir - self._start_disk requires_zip64 = None if centDirCount > ZIP_FILECOUNT_LIMIT: requires_zip64 = "Files count" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,10 @@ Library ------- +- Issue #26293: Fixed writing ZIP files that starts not from the start of the + file. Offsets in ZIP file now are relative to the start of the archive in + conforming to the specification. + - Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. - Issue #28322: Fixed possible crashes when unpickle itertools objects from -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:13:12 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:13:12 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI2Mjkz?= =?utf-8?q?=3A_Fixed_writing_ZIP_files_that_starts_not_from_the_start_of_t?= =?utf-8?q?he?= Message-ID: <20161007201312.17336.25411.D194D06A@psf.io> https://hg.python.org/cpython/rev/9a99a88301ef changeset: 104353:9a99a88301ef branch: 2.7 parent: 104346:47d5bf5a846f user: Serhiy Storchaka date: Fri Oct 07 23:12:53 2016 +0300 summary: Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. files: Lib/test/test_zipfile.py | 43 ++++++++++++++++++++++++++++ Lib/zipfile.py | 28 +++++++++-------- Misc/NEWS | 4 ++ 3 files changed, 62 insertions(+), 13 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 @@ -344,6 +344,49 @@ f.seek(len(data)) with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_read_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*10 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + self.assertEqual(zipfp.read(TESTFN), self.data) + + def test_append_to_concatenated_zip_file(self): + with io.BytesIO() as bio: + with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + zipfiledata = bio.getvalue() + data = b'I am not a ZipFile!'*1000000 + with open(TESTFN2, 'wb') as f: + f.write(data) + f.write(zipfiledata) + + with zipfile.ZipFile(TESTFN2, 'a') as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN]) + zipfp.writestr('strfile', self.data) + + with open(TESTFN2, 'rb') as f: + self.assertEqual(f.read(len(data)), data) + zipfiledata = f.read() + with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp: + self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile']) + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read('strfile'), self.data) def test_ignores_newline_at_end(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -772,6 +772,7 @@ # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True + self._start_disk = self.fp.tell() elif key == 'a': try: # See if file is a zip file @@ -785,6 +786,7 @@ # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True + self._start_disk = self.fp.tell() else: raise RuntimeError('Mode must be "r", "w" or "a"') except: @@ -815,17 +817,18 @@ offset_cd = endrec[_ECD_OFFSET] # offset of central directory self._comment = endrec[_ECD_COMMENT] # archive comment - # "concat" is zero, unless zip was concatenated to another file - concat = endrec[_ECD_LOCATION] - size_cd - offset_cd + # self._start_disk: Position of the start of ZIP archive + # It is zero, unless ZIP was concatenated to another file + self._start_disk = endrec[_ECD_LOCATION] - size_cd - offset_cd if endrec[_ECD_SIGNATURE] == stringEndArchive64: # If Zip64 extension structures are present, account for them - concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator) + self._start_disk -= (sizeEndCentDir64 + sizeEndCentDir64Locator) if self.debug > 2: - inferred = concat + offset_cd - print "given, inferred, offset", offset_cd, inferred, concat + inferred = self._start_disk + offset_cd + print "given, inferred, offset", offset_cd, inferred, self._start_disk # self.start_dir: Position of start of central directory - self.start_dir = offset_cd + concat + self.start_dir = offset_cd + self._start_disk fp.seek(self.start_dir, 0) data = fp.read(size_cd) fp = cStringIO.StringIO(data) @@ -855,7 +858,7 @@ t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) x._decodeExtra() - x.header_offset = x.header_offset + concat + x.header_offset = x.header_offset + self._start_disk x.filename = x._decodeFilename() self.filelist.append(x) self.NameToInfo[x.filename] = x @@ -1198,7 +1201,7 @@ raise RuntimeError('Compressed size larger than uncompressed size') # Seek backwards and write file header (which will now include # correct CRC and file sizes) - position = self.fp.tell() # Preserve current position in file + position = self.fp.tell() # Preserve current position in file self.fp.seek(zinfo.header_offset, 0) self.fp.write(zinfo.FileHeader(zip64)) self.fp.seek(position, 0) @@ -1284,11 +1287,10 @@ file_size = zinfo.file_size compress_size = zinfo.compress_size - if zinfo.header_offset > ZIP64_LIMIT: - extra.append(zinfo.header_offset) + header_offset = zinfo.header_offset - self._start_disk + if header_offset > ZIP64_LIMIT: + extra.append(header_offset) header_offset = 0xffffffffL - else: - header_offset = zinfo.header_offset extra_data = zinfo.extra if extra: @@ -1332,7 +1334,7 @@ # Write end-of-zip-archive record centDirCount = len(self.filelist) centDirSize = pos2 - pos1 - centDirOffset = pos1 + centDirOffset = pos1 - self._start_disk requires_zip64 = None if centDirCount > ZIP_FILECOUNT_LIMIT: requires_zip64 = "Files count" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,10 @@ Library ------- +- Issue #26293: Fixed writing ZIP files that starts not from the start of the + file. Offsets in ZIP file now are relative to the start of the archive in + conforming to the specification. + - Fix possible integer overflows and crashes in the mmap module with unusual usage patterns. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:27:07 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:27:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE4Mjg3?= =?utf-8?q?=3A_PyType=5FReady=28=29_now_checks_that_tp=5Fname_is_not_NULL?= =?utf-8?q?=2E?= Message-ID: <20161007202707.5074.5354.47A1551A@psf.io> https://hg.python.org/cpython/rev/5c459b0f2b75 changeset: 104354:5c459b0f2b75 branch: 3.5 parent: 104350:005704f5634f user: Serhiy Storchaka date: Fri Oct 07 23:24:35 2016 +0300 summary: Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. files: Doc/c-api/typeobj.rst | 3 ++- Doc/extending/newtypes.rst | 4 +++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Objects/typeobject.c | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -116,7 +116,8 @@ If no dot is present, the entire :c:member:`~PyTypeObject.tp_name` field is made accessible as the :attr:`~definition.__name__` attribute, and the :attr:`__module__` attribute is undefined (unless explicitly set in the dictionary, as explained above). This means your - type will be impossible to pickle. + type will be impossible to pickle. Additionally, it will not be listed in + module documentations created with pydoc. This field is not inherited by subtypes. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -129,7 +129,9 @@ Note that the name is a dotted name that includes both the module name and the name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. :: +the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. +One side effect of using an undotted name is that the pydoc documentation tool +will not list the new type in the module documentation. :: sizeof(noddy_NoddyObject), /* tp_basicsize */ diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -775,6 +775,7 @@ Kubilay Kocak Greg Kochanski Manvisha Kodali +Niklas Koep Damon Kohler Marko Kohtala Vajrasky Kok diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18287: PyType_Ready() now checks that tp_name is not NULL. + Original patch by Niklas Koep. + - Issue #24098: Fixed possible crash when AST is changed in process of compiling it. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4820,6 +4820,12 @@ _Py_AddToAllObjects((PyObject *)type, 0); #endif + if (type->tp_name == NULL) { + PyErr_Format(PyExc_SystemError, + "Type does not define the tp_name field."); + goto error; + } + /* Initialize tp_base (defaults to BaseObject unless that's us) */ base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:27:07 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:27:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4Mjg3?= =?utf-8?q?=3A_PyType=5FReady=28=29_now_checks_that_tp=5Fname_is_not_NULL?= =?utf-8?q?=2E?= Message-ID: <20161007202707.5225.68731.B5D3D970@psf.io> https://hg.python.org/cpython/rev/ba76dd106e66 changeset: 104355:ba76dd106e66 branch: 2.7 parent: 104353:9a99a88301ef user: Serhiy Storchaka date: Fri Oct 07 23:24:35 2016 +0300 summary: Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. files: Doc/c-api/typeobj.rst | 3 ++- Doc/extending/newtypes.rst | 4 +++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Objects/typeobject.c | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -122,7 +122,8 @@ If no dot is present, the entire :c:member:`~PyTypeObject.tp_name` field is made accessible as the :attr:`~definition.__name__` attribute, and the :attr:`__module__` attribute is undefined (unless explicitly set in the dictionary, as explained above). This means your - type will be impossible to pickle. + type will be impossible to pickle. Additionally, it will not be listed in + module documentations created with pydoc. This field is not inherited by subtypes. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -140,7 +140,9 @@ Note that the name is a dotted name that includes both the module name and the name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. :: +the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. +One side effect of using an undotted name is that the pydoc documentation tool +will not list the new type in the module documentation. :: sizeof(noddy_NoddyObject), /* tp_basicsize */ diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -733,6 +733,7 @@ Kubilay Kocak Greg Kochanski Manvisha Kodali +Niklas Koep Damon Kohler Marko Kohtala Vajrasky Kok diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18287: PyType_Ready() now checks that tp_name is not NULL. + Original patch by Niklas Koep. + - Issue #24098: Fixed possible crash when AST is changed in process of compiling it. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4066,6 +4066,12 @@ _Py_AddToAllObjects((PyObject *)type, 0); #endif + if (type->tp_name == NULL) { + PyErr_Format(PyExc_SystemError, + "Type does not define the tp_name field."); + goto error; + } + /* Initialize tp_base (defaults to BaseObject unless that's us) */ base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:27:07 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:27:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2318287=3A_PyType=5FReady=28=29_now_checks_that_tp=5Fna?= =?utf-8?q?me_is_not_NULL=2E?= Message-ID: <20161007202707.17363.83663.130DF6F0@psf.io> https://hg.python.org/cpython/rev/0b726193ec3c changeset: 104356:0b726193ec3c branch: 3.6 parent: 104351:b06e75ae1981 parent: 104354:5c459b0f2b75 user: Serhiy Storchaka date: Fri Oct 07 23:25:46 2016 +0300 summary: Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. files: Doc/c-api/typeobj.rst | 3 ++- Doc/extending/newtypes.rst | 4 +++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Objects/typeobject.c | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -116,7 +116,8 @@ If no dot is present, the entire :c:member:`~PyTypeObject.tp_name` field is made accessible as the :attr:`~definition.__name__` attribute, and the :attr:`__module__` attribute is undefined (unless explicitly set in the dictionary, as explained above). This means your - type will be impossible to pickle. + type will be impossible to pickle. Additionally, it will not be listed in + module documentations created with pydoc. This field is not inherited by subtypes. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -129,7 +129,9 @@ Note that the name is a dotted name that includes both the module name and the name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. :: +the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. +One side effect of using an undotted name is that the pydoc documentation tool +will not list the new type in the module documentation. :: sizeof(noddy_NoddyObject), /* tp_basicsize */ diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -783,6 +783,7 @@ Kubilay Kocak Greg Kochanski Manvisha Kodali +Niklas Koep Damon Kohler Marko Kohtala Vajrasky Kok diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18287: PyType_Ready() now checks that tp_name is not NULL. + Original patch by Niklas Koep. + - Issue #24098: Fixed possible crash when AST is changed in process of compiling it. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4893,6 +4893,12 @@ _Py_AddToAllObjects((PyObject *)type, 0); #endif + if (type->tp_name == NULL) { + PyErr_Format(PyExc_SystemError, + "Type does not define the tp_name field."); + goto error; + } + /* Initialize tp_base (defaults to BaseObject unless that's us) */ base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:27:07 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:27:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318287=3A_PyType=5FReady=28=29_now_checks_that_t?= =?utf-8?q?p=5Fname_is_not_NULL=2E?= Message-ID: <20161007202707.17589.95918.8EE70474@psf.io> https://hg.python.org/cpython/rev/a60d0e80cc1d changeset: 104357:a60d0e80cc1d parent: 104352:64a19fe3a16a parent: 104356:0b726193ec3c user: Serhiy Storchaka date: Fri Oct 07 23:26:16 2016 +0300 summary: Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. files: Doc/c-api/typeobj.rst | 3 ++- Doc/extending/newtypes.rst | 4 +++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Objects/typeobject.c | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -116,7 +116,8 @@ If no dot is present, the entire :c:member:`~PyTypeObject.tp_name` field is made accessible as the :attr:`~definition.__name__` attribute, and the :attr:`__module__` attribute is undefined (unless explicitly set in the dictionary, as explained above). This means your - type will be impossible to pickle. + type will be impossible to pickle. Additionally, it will not be listed in + module documentations created with pydoc. This field is not inherited by subtypes. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -129,7 +129,9 @@ Note that the name is a dotted name that includes both the module name and the name of the type within the module. The module in this case is :mod:`noddy` and -the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. :: +the type is :class:`Noddy`, so we set the type name to :class:`noddy.Noddy`. +One side effect of using an undotted name is that the pydoc documentation tool +will not list the new type in the module documentation. :: sizeof(noddy_NoddyObject), /* tp_basicsize */ diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -784,6 +784,7 @@ Kubilay Kocak Greg Kochanski Manvisha Kodali +Niklas Koep Damon Kohler Marko Kohtala Vajrasky Kok diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #18287: PyType_Ready() now checks that tp_name is not NULL. + Original patch by Niklas Koep. + - Issue #24098: Fixed possible crash when AST is changed in process of compiling it. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4893,6 +4893,12 @@ _Py_AddToAllObjects((PyObject *)type, 0); #endif + if (type->tp_name == NULL) { + PyErr_Format(PyExc_SystemError, + "Type does not define the tp_name field."); + goto error; + } + /* Initialize tp_base (defaults to BaseObject unless that's us) */ base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:35:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:35:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MjU3?= =?utf-8?q?=3A_Improved_error_message_when_pass_a_non-mapping_as_a_var-key?= =?utf-8?q?word?= Message-ID: <20161007203521.20073.87190.42D44708@psf.io> https://hg.python.org/cpython/rev/35676cd72352 changeset: 104358:35676cd72352 branch: 3.5 parent: 104354:5c459b0f2b75 user: Serhiy Storchaka date: Fri Oct 07 23:32:41 2016 +0300 summary: Issue #28257: Improved error message when pass a non-mapping as a var-keyword argument. files: Lib/test/test_extcall.py | 10 ++++++++++ Python/ceval.c | 21 +++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -269,6 +269,16 @@ ... TypeError: h() argument after ** must be a mapping, not list + >>> h(**{'a': 1}, **h) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not function + + >>> h(**{'a': 1}, **[]) + Traceback (most recent call last): + ... + TypeError: h() argument after ** must be a mapping, not list + >>> dir(**h) Traceback (most recent call last): ... diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2663,7 +2663,8 @@ PyObject *intersection = _PyDictView_Intersect(sum, arg); if (intersection == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + if (PyErr_ExceptionMatches(PyExc_AttributeError) || + !PyMapping_Check(arg)) { int function_location = (oparg>>8) & 0xff; PyObject *func = ( PEEK(function_location + num_maps)); @@ -2707,9 +2708,21 @@ if (PyDict_Update(sum, arg) < 0) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping", - arg->ob_type->tp_name); + if (with_call) { + int function_location = (oparg>>8) & 0xff; + PyObject *func = PEEK(function_location + num_maps); + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after ** " + "must be a mapping, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + arg->ob_type->tp_name); + } + else { + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not a mapping", + arg->ob_type->tp_name); + } } Py_DECREF(sum); goto error; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:35:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:35:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161007203521.15320.91631.F7F72478@psf.io> https://hg.python.org/cpython/rev/0cb46cfb540d changeset: 104360:0cb46cfb540d parent: 104357:a60d0e80cc1d parent: 104359:67a4a6184058 user: Serhiy Storchaka date: Fri Oct 07 23:34:12 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:35:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:35:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Null_merge?= Message-ID: <20161007203521.1540.4653.7EF18C94@psf.io> https://hg.python.org/cpython/rev/67a4a6184058 changeset: 104359:67a4a6184058 branch: 3.6 parent: 104356:0b726193ec3c parent: 104358:35676cd72352 user: Serhiy Storchaka date: Fri Oct 07 23:33:55 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:47:38 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:47:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI1Nzgz?= =?utf-8?q?=3A_Fixed_test=5Ftraceback_when_run_directly_=28without_regrtes?= =?utf-8?b?dCku?= Message-ID: <20161007204738.20073.24193.DF21C494@psf.io> https://hg.python.org/cpython/rev/8d150de9edba changeset: 104361:8d150de9edba branch: 3.5 parent: 104358:35676cd72352 user: Serhiy Storchaka date: Fri Oct 07 23:45:42 2016 +0300 summary: Issue #25783: Fixed test_traceback when run directly (without regrtest). files: Lib/test/test_traceback.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -688,8 +688,12 @@ class TestStack(unittest.TestCase): def test_walk_stack(self): - s = list(traceback.walk_stack(None)) - self.assertGreater(len(s), 10) + def deeper(): + return list(traceback.walk_stack(None)) + s1 = list(traceback.walk_stack(None)) + s2 = deeper() + self.assertEqual(len(s2) - len(s1), 1) + self.assertEqual(s2[1:], s1) def test_walk_tb(self): try: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:47:38 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:47:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2325783=3A_Fixed_test=5Ftraceback_when_run_directly_=28?= =?utf-8?q?without_regrtest=29=2E?= Message-ID: <20161007204738.85635.90849.381016BE@psf.io> https://hg.python.org/cpython/rev/4646b64139c9 changeset: 104362:4646b64139c9 branch: 3.6 parent: 104359:67a4a6184058 parent: 104361:8d150de9edba user: Serhiy Storchaka date: Fri Oct 07 23:46:22 2016 +0300 summary: Issue #25783: Fixed test_traceback when run directly (without regrtest). files: Lib/test/test_traceback.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -819,8 +819,12 @@ class TestStack(unittest.TestCase): def test_walk_stack(self): - s = list(traceback.walk_stack(None)) - self.assertGreater(len(s), 10) + def deeper(): + return list(traceback.walk_stack(None)) + s1 = list(traceback.walk_stack(None)) + s2 = deeper() + self.assertEqual(len(s2) - len(s1), 1) + self.assertEqual(s2[1:], s1) def test_walk_tb(self): try: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 7 16:47:38 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Oct 2016 20:47:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2325783=3A_Fixed_test=5Ftraceback_when_run_direct?= =?utf-8?q?ly_=28without_regrtest=29=2E?= Message-ID: <20161007204738.94968.9910.9C97F96F@psf.io> https://hg.python.org/cpython/rev/696851f38c93 changeset: 104363:696851f38c93 parent: 104360:0cb46cfb540d parent: 104362:4646b64139c9 user: Serhiy Storchaka date: Fri Oct 07 23:47:17 2016 +0300 summary: Issue #25783: Fixed test_traceback when run directly (without regrtest). files: Lib/test/test_traceback.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -819,8 +819,12 @@ class TestStack(unittest.TestCase): def test_walk_stack(self): - s = list(traceback.walk_stack(None)) - self.assertGreater(len(s), 10) + def deeper(): + return list(traceback.walk_stack(None)) + s1 = list(traceback.walk_stack(None)) + s2 = deeper() + self.assertEqual(len(s2) - len(s1), 1) + self.assertEqual(s2[1:], s1) def test_walk_tb(self): try: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 02:58:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 06:58:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Silenced_compi?= =?utf-8?q?ler_warnings=2E?= Message-ID: <20161008065827.85673.50366.88A04805@psf.io> https://hg.python.org/cpython/rev/4ed5f0e9bba2 changeset: 104364:4ed5f0e9bba2 branch: 2.7 parent: 104355:ba76dd106e66 user: Serhiy Storchaka date: Sat Oct 08 09:58:08 2016 +0300 summary: Silenced compiler warnings. files: Modules/getpath.c | 8 +++----- Modules/socketmodule.c | 8 ++++---- Objects/codeobject.c | 1 - Parser/pgen.c | 5 +++-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -329,11 +329,9 @@ n = fread(rel_builddir_path, 1, MAXPATHLEN, f); rel_builddir_path[n] = '\0'; fclose(f); - if (n >= 0) { - strcpy(exec_prefix, argv0_path); - joinpath(exec_prefix, rel_builddir_path); - return -1; - } + strcpy(exec_prefix, argv0_path); + joinpath(exec_prefix, rel_builddir_path); + return -1; } } diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3472,7 +3472,7 @@ int buf_len = (sizeof buf) - 1; int errnop; #endif -#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG) +#ifdef HAVE_GETHOSTBYNAME_R_3_ARG int result; #endif #endif /* HAVE_GETHOSTBYNAME_R */ @@ -3484,7 +3484,7 @@ Py_BEGIN_ALLOW_THREADS #ifdef HAVE_GETHOSTBYNAME_R #if defined(HAVE_GETHOSTBYNAME_R_6_ARG) - result = gethostbyname_r(name, &hp_allocated, buf, buf_len, + gethostbyname_r(name, &hp_allocated, buf, buf_len, &h, &errnop); #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) h = gethostbyname_r(name, &hp_allocated, buf, buf_len, &errnop); @@ -3548,7 +3548,7 @@ int buf_len = (sizeof buf) - 1; int errnop; #endif -#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG) +#ifdef HAVE_GETHOSTBYNAME_R_3_ARG int result; #endif #endif /* HAVE_GETHOSTBYNAME_R */ @@ -3581,7 +3581,7 @@ Py_BEGIN_ALLOW_THREADS #ifdef HAVE_GETHOSTBYNAME_R #if defined(HAVE_GETHOSTBYNAME_R_6_ARG) - result = gethostbyaddr_r(ap, al, af, + gethostbyaddr_r(ap, al, af, &hp_allocated, buf, buf_len, &h, &errnop); #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) diff --git a/Objects/codeobject.c b/Objects/codeobject.c --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -95,7 +95,6 @@ PyObject *lnotab) { PyCodeObject *co; - Py_ssize_t i; /* Check argument types */ if (argcount < 0 || nlocals < 0 || code == NULL || diff --git a/Parser/pgen.c b/Parser/pgen.c --- a/Parser/pgen.c +++ b/Parser/pgen.c @@ -136,11 +136,12 @@ static char REQNFMT[] = "metacompile: less than %d children\n"; -#define REQN(i, count) \ +#define REQN(i, count) do { \ if (i < count) { \ fprintf(stderr, REQNFMT, count); \ Py_FatalError("REQN"); \ - } else + } \ +} while (0) #else #define REQN(i, count) /* empty */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 05:28:51 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 09:28:51 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2OTA2?= =?utf-8?q?=3A_Resolving_special_methods_of_uninitialized_type_now_causes?= Message-ID: <20161008092851.17589.34625.160E38BF@psf.io> https://hg.python.org/cpython/rev/bbaf6c928526 changeset: 104365:bbaf6c928526 branch: 3.5 parent: 104361:8d150de9edba user: Serhiy Storchaka date: Sat Oct 08 12:24:09 2016 +0300 summary: Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. files: Misc/NEWS | 3 +++ Objects/typeobject.c | 24 +++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #26906: Resolving special methods of uninitialized type now causes + implicit initialization of the type instead of a fail. + - Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2869,11 +2869,25 @@ /* Look in tp_dict of types in MRO */ mro = type->tp_mro; - /* If mro is NULL, the type is either not yet initialized - by PyType_Ready(), or already cleared by type_clear(). - Either way the safest thing to do is to return NULL. */ - if (mro == NULL) - return NULL; + if (mro == NULL) { + if ((type->tp_flags & Py_TPFLAGS_READYING) == 0 && + PyType_Ready(type) < 0) { + /* It's not ideal to clear the error condition, + but this function is documented as not setting + an exception, and I don't want to change that. + When PyType_Ready() can't proceed, it won't + set the "ready" flag, so future attempts to ready + the same type will call it again -- hopefully + in a context that propagates the exception out. + */ + PyErr_Clear(); + return NULL; + } + mro = type->tp_mro; + if (mro == NULL) { + return NULL; + } + } res = NULL; /* keep a strong reference to mro because type->tp_mro can be replaced -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 05:28:51 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 09:28:51 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI2OTA2?= =?utf-8?q?=3A_Resolving_special_methods_of_uninitialized_type_now_causes?= Message-ID: <20161008092851.95121.28521.10CE6080@psf.io> https://hg.python.org/cpython/rev/3119f08802a5 changeset: 104366:3119f08802a5 branch: 2.7 parent: 104364:4ed5f0e9bba2 user: Serhiy Storchaka date: Sat Oct 08 12:24:09 2016 +0300 summary: Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. files: Misc/NEWS | 3 +++ Objects/typeobject.c | 24 +++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #26906: Resolving special methods of uninitialized type now causes + implicit initialization of the type instead of a fail. + - Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2545,11 +2545,25 @@ /* Look in tp_dict of types in MRO */ mro = type->tp_mro; - /* If mro is NULL, the type is either not yet initialized - by PyType_Ready(), or already cleared by type_clear(). - Either way the safest thing to do is to return NULL. */ - if (mro == NULL) - return NULL; + if (mro == NULL) { + if ((type->tp_flags & Py_TPFLAGS_READYING) == 0 && + PyType_Ready(type) < 0) { + /* It's not ideal to clear the error condition, + but this function is documented as not setting + an exception, and I don't want to change that. + When PyType_Ready() can't proceed, it won't + set the "ready" flag, so future attempts to ready + the same type will call it again -- hopefully + in a context that propagates the exception out. + */ + PyErr_Clear(); + return NULL; + } + mro = type->tp_mro; + if (mro == NULL) { + return NULL; + } + } res = NULL; assert(PyTuple_Check(mro)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 05:28:52 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 09:28:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326906=3A_Resolving_special_methods_of_uninitial?= =?utf-8?q?ized_type_now_causes?= Message-ID: <20161008092852.79450.21635.5833AF72@psf.io> https://hg.python.org/cpython/rev/d24f1467a297 changeset: 104368:d24f1467a297 parent: 104363:696851f38c93 parent: 104367:888a26fac9d2 user: Serhiy Storchaka date: Sat Oct 08 12:28:25 2016 +0300 summary: Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. files: Misc/NEWS | 3 +++ Objects/typeobject.c | 24 +++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #26906: Resolving special methods of uninitialized type now causes + implicit initialization of the type instead of a fail. + - Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2914,11 +2914,25 @@ /* Look in tp_dict of types in MRO */ mro = type->tp_mro; - /* If mro is NULL, the type is either not yet initialized - by PyType_Ready(), or already cleared by type_clear(). - Either way the safest thing to do is to return NULL. */ - if (mro == NULL) - return NULL; + if (mro == NULL) { + if ((type->tp_flags & Py_TPFLAGS_READYING) == 0 && + PyType_Ready(type) < 0) { + /* It's not ideal to clear the error condition, + but this function is documented as not setting + an exception, and I don't want to change that. + When PyType_Ready() can't proceed, it won't + set the "ready" flag, so future attempts to ready + the same type will call it again -- hopefully + in a context that propagates the exception out. + */ + PyErr_Clear(); + return NULL; + } + mro = type->tp_mro; + if (mro == NULL) { + return NULL; + } + } res = NULL; /* keep a strong reference to mro because type->tp_mro can be replaced -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 05:28:52 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 09:28:52 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2326906=3A_Resolving_special_methods_of_uninitialized_t?= =?utf-8?q?ype_now_causes?= Message-ID: <20161008092852.20644.97842.7620631B@psf.io> https://hg.python.org/cpython/rev/888a26fac9d2 changeset: 104367:888a26fac9d2 branch: 3.6 parent: 104362:4646b64139c9 parent: 104365:bbaf6c928526 user: Serhiy Storchaka date: Sat Oct 08 12:26:25 2016 +0300 summary: Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. files: Misc/NEWS | 3 +++ Objects/typeobject.c | 24 +++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #26906: Resolving special methods of uninitialized type now causes + implicit initialization of the type instead of a fail. + - Issue #18287: PyType_Ready() now checks that tp_name is not NULL. Original patch by Niklas Koep. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2914,11 +2914,25 @@ /* Look in tp_dict of types in MRO */ mro = type->tp_mro; - /* If mro is NULL, the type is either not yet initialized - by PyType_Ready(), or already cleared by type_clear(). - Either way the safest thing to do is to return NULL. */ - if (mro == NULL) - return NULL; + if (mro == NULL) { + if ((type->tp_flags & Py_TPFLAGS_READYING) == 0 && + PyType_Ready(type) < 0) { + /* It's not ideal to clear the error condition, + but this function is documented as not setting + an exception, and I don't want to change that. + When PyType_Ready() can't proceed, it won't + set the "ready" flag, so future attempts to ready + the same type will call it again -- hopefully + in a context that propagates the exception out. + */ + PyErr_Clear(); + return NULL; + } + mro = type->tp_mro; + if (mro == NULL) { + return NULL; + } + } res = NULL; /* keep a strong reference to mro because type->tp_mro can be replaced -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 05:35:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 09:35:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzE3?= =?utf-8?q?=3A_The_disassembler_now_decodes_FORMAT=5FVALUE_argument=2E?= Message-ID: <20161008093521.15249.84222.5ACE3A47@psf.io> https://hg.python.org/cpython/rev/5e81d14a52f7 changeset: 104369:5e81d14a52f7 branch: 3.6 parent: 104367:888a26fac9d2 user: Serhiy Storchaka date: Sat Oct 08 12:34:25 2016 +0300 summary: Issue #28317: The disassembler now decodes FORMAT_VALUE argument. files: Lib/dis.py | 9 +++++++++ Lib/test/test_dis.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 35 insertions(+), 0 deletions(-) diff --git a/Lib/dis.py b/Lib/dis.py --- a/Lib/dis.py +++ b/Lib/dis.py @@ -16,6 +16,8 @@ _have_code = (types.MethodType, types.FunctionType, types.CodeType, classmethod, staticmethod, type) +FORMAT_VALUE = opmap['FORMAT_VALUE'] + def _try_compile(source, name): """Attempts to compile the given source, first as an expression and then as a statement if the first approach fails. @@ -314,6 +316,13 @@ argrepr = argval elif op in hasfree: argval, argrepr = _get_name_info(arg, cells) + elif op == FORMAT_VALUE: + argval = ((None, str, repr, ascii)[arg & 0x3], bool(arg & 0x4)) + argrepr = ('', 'str', 'repr', 'ascii')[arg & 0x3] + if argval[1]: + if argrepr: + argrepr += ', ' + argrepr += 'with format' yield Instruction(opname[op], op, arg, argval, argrepr, offset, starts_line, is_jump_target) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -301,6 +301,27 @@ TRACEBACK_CODE.co_firstlineno + 4, TRACEBACK_CODE.co_firstlineno + 5) +def _fstring(a, b, c, d): + return f'{a} {b:4} {c!r} {d!r:4}' + +dis_fstring = """\ +%3d 0 LOAD_FAST 0 (a) + 2 FORMAT_VALUE 0 + 4 LOAD_CONST 1 (' ') + 6 LOAD_FAST 1 (b) + 8 LOAD_CONST 2 ('4') + 10 FORMAT_VALUE 4 (with format) + 12 LOAD_CONST 1 (' ') + 14 LOAD_FAST 2 (c) + 16 FORMAT_VALUE 2 (repr) + 18 LOAD_CONST 1 (' ') + 20 LOAD_FAST 3 (d) + 22 LOAD_CONST 2 ('4') + 24 FORMAT_VALUE 6 (repr, with format) + 26 BUILD_STRING 7 + 28 RETURN_VALUE +""" % (_fstring.__code__.co_firstlineno + 1,) + def _g(x): yield x @@ -404,6 +425,9 @@ gen_disas = self.get_disassembly(_g(1)) # Disassemble generator itself self.assertEqual(gen_disas, gen_func_disas) + def test_disassemble_fstring(self): + self.do_disassembly_test(_fstring, dis_fstring) + def test_dis_none(self): try: del sys.last_traceback diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -62,6 +62,8 @@ Library ------- +- Issue #28317: The disassembler now decodes FORMAT_VALUE argument. + - Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 05:35:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 09:35:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328317=3A_The_disassembler_now_decodes_FORMAT=5F?= =?utf-8?q?VALUE_argument=2E?= Message-ID: <20161008093521.15398.4949.767E6AC6@psf.io> https://hg.python.org/cpython/rev/085944763f3a changeset: 104370:085944763f3a parent: 104368:d24f1467a297 parent: 104369:5e81d14a52f7 user: Serhiy Storchaka date: Sat Oct 08 12:34:59 2016 +0300 summary: Issue #28317: The disassembler now decodes FORMAT_VALUE argument. files: Lib/dis.py | 9 +++++++++ Lib/test/test_dis.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 35 insertions(+), 0 deletions(-) diff --git a/Lib/dis.py b/Lib/dis.py --- a/Lib/dis.py +++ b/Lib/dis.py @@ -16,6 +16,8 @@ _have_code = (types.MethodType, types.FunctionType, types.CodeType, classmethod, staticmethod, type) +FORMAT_VALUE = opmap['FORMAT_VALUE'] + def _try_compile(source, name): """Attempts to compile the given source, first as an expression and then as a statement if the first approach fails. @@ -314,6 +316,13 @@ argrepr = argval elif op in hasfree: argval, argrepr = _get_name_info(arg, cells) + elif op == FORMAT_VALUE: + argval = ((None, str, repr, ascii)[arg & 0x3], bool(arg & 0x4)) + argrepr = ('', 'str', 'repr', 'ascii')[arg & 0x3] + if argval[1]: + if argrepr: + argrepr += ', ' + argrepr += 'with format' yield Instruction(opname[op], op, arg, argval, argrepr, offset, starts_line, is_jump_target) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -301,6 +301,27 @@ TRACEBACK_CODE.co_firstlineno + 4, TRACEBACK_CODE.co_firstlineno + 5) +def _fstring(a, b, c, d): + return f'{a} {b:4} {c!r} {d!r:4}' + +dis_fstring = """\ +%3d 0 LOAD_FAST 0 (a) + 2 FORMAT_VALUE 0 + 4 LOAD_CONST 1 (' ') + 6 LOAD_FAST 1 (b) + 8 LOAD_CONST 2 ('4') + 10 FORMAT_VALUE 4 (with format) + 12 LOAD_CONST 1 (' ') + 14 LOAD_FAST 2 (c) + 16 FORMAT_VALUE 2 (repr) + 18 LOAD_CONST 1 (' ') + 20 LOAD_FAST 3 (d) + 22 LOAD_CONST 2 ('4') + 24 FORMAT_VALUE 6 (repr, with format) + 26 BUILD_STRING 7 + 28 RETURN_VALUE +""" % (_fstring.__code__.co_firstlineno + 1,) + def _g(x): yield x @@ -404,6 +425,9 @@ gen_disas = self.get_disassembly(_g(1)) # Disassemble generator itself self.assertEqual(gen_disas, gen_func_disas) + def test_disassemble_fstring(self): + self.do_disassembly_test(_fstring, dis_fstring) + def test_dis_none(self): try: del sys.last_traceback diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -70,6 +70,8 @@ Library ------- +- Issue #28317: The disassembler now decodes FORMAT_VALUE argument. + - Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 09:15:44 2016 From: python-checkins at python.org (berker.peksag) Date: Sat, 08 Oct 2016 13:15:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4Mzkw?= =?utf-8?q?=3A_Fix_header_levels_in_whatsnew/3=2E6=2Erst?= Message-ID: <20161008131544.82319.45210.21C439B3@psf.io> https://hg.python.org/cpython/rev/3ee15bd35902 changeset: 104371:3ee15bd35902 branch: 3.6 parent: 104369:5e81d14a52f7 user: Berker Peksag date: Sat Oct 08 16:15:15 2016 +0300 summary: Issue #28390: Fix header levels in whatsnew/3.6.rst Patch by SilentGhost. files: Doc/whatsnew/3.6.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -163,7 +163,7 @@ .. _pep-515: PEP 515: Underscores in Numeric Literals -======================================== +---------------------------------------- Prior to PEP 515, there was no support for writing long numeric literals with some form of separator to improve readability. For @@ -300,7 +300,7 @@ .. _variable-annotations: PEP 526: Syntax for variable annotations -======================================== +---------------------------------------- :pep:`484` introduced standard for type annotations of function parameters, a.k.a. type hints. This PEP adds syntax to Python for annotating the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 09:15:44 2016 From: python-checkins at python.org (berker.peksag) Date: Sat, 08 Oct 2016 13:15:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328390=3A_Merge_from_3=2E6?= Message-ID: <20161008131544.95094.67504.4EC0A598@psf.io> https://hg.python.org/cpython/rev/43b1b3c883ff changeset: 104372:43b1b3c883ff parent: 104370:085944763f3a parent: 104371:3ee15bd35902 user: Berker Peksag date: Sat Oct 08 16:15:38 2016 +0300 summary: Issue #28390: Merge from 3.6 files: Doc/whatsnew/3.6.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -164,7 +164,7 @@ .. _pep-515: PEP 515: Underscores in Numeric Literals -======================================== +---------------------------------------- Prior to PEP 515, there was no support for writing long numeric literals with some form of separator to improve readability. For @@ -301,7 +301,7 @@ .. _variable-annotations: PEP 526: Syntax for variable annotations -======================================== +---------------------------------------- :pep:`484` introduced standard for type annotations of function parameters, a.k.a. type hints. This PEP adds syntax to Python for annotating the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 13:17:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 17:17:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327998=3A_Fixed_bytes_path_support_in_os=2Escand?= =?utf-8?q?ir=28=29_on_Windows=2E?= Message-ID: <20161008171744.20553.96948.B9C6B77E@psf.io> https://hg.python.org/cpython/rev/837114dea493 changeset: 104374:837114dea493 parent: 104372:43b1b3c883ff parent: 104373:4ed634870a9a user: Serhiy Storchaka date: Sat Oct 08 20:17:26 2016 +0300 summary: Issue #27998: Fixed bytes path support in os.scandir() on Windows. Patch by Eryk Sun. files: Misc/NEWS | 3 + Modules/posixmodule.c | 109 ++++++++++++++--------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -70,6 +70,9 @@ Library ------- +- Issue #27998: Fixed bytes path support in os.scandir() on Windows. + Patch by Eryk Sun. + - Issue #28317: The disassembler now decodes FORMAT_VALUE argument. - Issue #26293: Fixed writing ZIP files that starts not from the start of the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1337,27 +1337,37 @@ #endif /* MS_WINDOWS */ static PyObject * +path_object_error(PyObject *path) +{ +#ifdef MS_WINDOWS + return PyErr_SetExcFromWindowsErrWithFilenameObject( + PyExc_OSError, 0, path); +#else + return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); +#endif +} + +static PyObject * +path_object_error2(PyObject *path, PyObject *path2) +{ +#ifdef MS_WINDOWS + return PyErr_SetExcFromWindowsErrWithFilenameObjects( + PyExc_OSError, 0, path, path2); +#else + return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path, path2); +#endif +} + +static PyObject * path_error(path_t *path) { -#ifdef MS_WINDOWS - return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, - 0, path->object); -#else - return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); -#endif -} - + return path_object_error(path->object); +} static PyObject * path_error2(path_t *path, path_t *path2) { -#ifdef MS_WINDOWS - return PyErr_SetExcFromWindowsErrWithFilenameObjects(PyExc_OSError, - 0, path->object, path2->object); -#else - return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, - path->object, path2->object); -#endif + return path_object_error2(path->object, path2->object); } @@ -11152,41 +11162,26 @@ DirEntry_fetch_stat(DirEntry *self, int follow_symlinks) { int result; - struct _Py_stat_struct st; - -#ifdef MS_WINDOWS - const wchar_t *path; - - path = PyUnicode_AsUnicode(self->path); - if (!path) - return NULL; - - if (follow_symlinks) - result = win32_stat(path, &st); - else - result = win32_lstat(path, &st); - - if (result != 0) { - return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, - 0, self->path); - } + STRUCT_STAT st; + PyObject *ub; + +#ifdef MS_WINDOWS + if (PyUnicode_FSDecoder(self->path, &ub)) { + const wchar_t *path = PyUnicode_AsUnicode(ub); #else /* POSIX */ - PyObject *bytes; - const char *path; - - if (!PyUnicode_FSConverter(self->path, &bytes)) - return NULL; - path = PyBytes_AS_STRING(bytes); - - if (follow_symlinks) - result = STAT(path, &st); - else - result = LSTAT(path, &st); - Py_DECREF(bytes); + if (PyUnicode_FSConverter(self->path, &ub)) { + const char *path = PyBytes_AS_STRING(ub); +#endif + if (follow_symlinks) + result = STAT(path, &st); + else + result = LSTAT(path, &st); + Py_DECREF(ub); + } else + return NULL; if (result != 0) - return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, self->path); -#endif + return path_object_error(self->path); return _pystat_fromstructstat(&st); } @@ -11356,17 +11351,19 @@ { #ifdef MS_WINDOWS if (!self->got_file_index) { + PyObject *unicode; const wchar_t *path; - struct _Py_stat_struct stat; - - path = PyUnicode_AsUnicode(self->path); - if (!path) + STRUCT_STAT stat; + int result; + + if (!PyUnicode_FSDecoder(self->path, &unicode)) return NULL; - - if (win32_lstat(path, &stat) != 0) { - return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, - 0, self->path); - } + path = PyUnicode_AsUnicode(unicode); + result = LSTAT(path, &stat); + Py_DECREF(unicode); + + if (result != 0) + return path_object_error(self->path); self->win32_file_index = stat.st_ino; self->got_file_index = 1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 13:17:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 17:17:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI3OTk4?= =?utf-8?q?=3A_Fixed_bytes_path_support_in_os=2Escandir=28=29_on_Windows?= =?utf-8?q?=2E?= Message-ID: <20161008171744.75793.46820.152B0034@psf.io> https://hg.python.org/cpython/rev/4ed634870a9a changeset: 104373:4ed634870a9a branch: 3.6 parent: 104371:3ee15bd35902 user: Serhiy Storchaka date: Sat Oct 08 20:16:57 2016 +0300 summary: Issue #27998: Fixed bytes path support in os.scandir() on Windows. Patch by Eryk Sun. files: Misc/NEWS | 3 + Modules/posixmodule.c | 109 ++++++++++++++--------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -62,6 +62,9 @@ Library ------- +- Issue #27998: Fixed bytes path support in os.scandir() on Windows. + Patch by Eryk Sun. + - Issue #28317: The disassembler now decodes FORMAT_VALUE argument. - Issue #26293: Fixed writing ZIP files that starts not from the start of the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1337,27 +1337,37 @@ #endif /* MS_WINDOWS */ static PyObject * +path_object_error(PyObject *path) +{ +#ifdef MS_WINDOWS + return PyErr_SetExcFromWindowsErrWithFilenameObject( + PyExc_OSError, 0, path); +#else + return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); +#endif +} + +static PyObject * +path_object_error2(PyObject *path, PyObject *path2) +{ +#ifdef MS_WINDOWS + return PyErr_SetExcFromWindowsErrWithFilenameObjects( + PyExc_OSError, 0, path, path2); +#else + return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path, path2); +#endif +} + +static PyObject * path_error(path_t *path) { -#ifdef MS_WINDOWS - return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, - 0, path->object); -#else - return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); -#endif -} - + return path_object_error(path->object); +} static PyObject * path_error2(path_t *path, path_t *path2) { -#ifdef MS_WINDOWS - return PyErr_SetExcFromWindowsErrWithFilenameObjects(PyExc_OSError, - 0, path->object, path2->object); -#else - return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, - path->object, path2->object); -#endif + return path_object_error2(path->object, path2->object); } @@ -11152,41 +11162,26 @@ DirEntry_fetch_stat(DirEntry *self, int follow_symlinks) { int result; - struct _Py_stat_struct st; - -#ifdef MS_WINDOWS - const wchar_t *path; - - path = PyUnicode_AsUnicode(self->path); - if (!path) - return NULL; - - if (follow_symlinks) - result = win32_stat(path, &st); - else - result = win32_lstat(path, &st); - - if (result != 0) { - return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, - 0, self->path); - } + STRUCT_STAT st; + PyObject *ub; + +#ifdef MS_WINDOWS + if (PyUnicode_FSDecoder(self->path, &ub)) { + const wchar_t *path = PyUnicode_AsUnicode(ub); #else /* POSIX */ - PyObject *bytes; - const char *path; - - if (!PyUnicode_FSConverter(self->path, &bytes)) - return NULL; - path = PyBytes_AS_STRING(bytes); - - if (follow_symlinks) - result = STAT(path, &st); - else - result = LSTAT(path, &st); - Py_DECREF(bytes); + if (PyUnicode_FSConverter(self->path, &ub)) { + const char *path = PyBytes_AS_STRING(ub); +#endif + if (follow_symlinks) + result = STAT(path, &st); + else + result = LSTAT(path, &st); + Py_DECREF(ub); + } else + return NULL; if (result != 0) - return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, self->path); -#endif + return path_object_error(self->path); return _pystat_fromstructstat(&st); } @@ -11356,17 +11351,19 @@ { #ifdef MS_WINDOWS if (!self->got_file_index) { + PyObject *unicode; const wchar_t *path; - struct _Py_stat_struct stat; - - path = PyUnicode_AsUnicode(self->path); - if (!path) + STRUCT_STAT stat; + int result; + + if (!PyUnicode_FSDecoder(self->path, &unicode)) return NULL; - - if (win32_lstat(path, &stat) != 0) { - return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, - 0, self->path); - } + path = PyUnicode_AsUnicode(unicode); + result = LSTAT(path, &stat); + Py_DECREF(unicode); + + if (result != 0) + return path_object_error(self->path); self->win32_file_index = stat.st_ino; self->got_file_index = 1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:31 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjYu?= Message-ID: <20161008190831.15793.34655.6DF674A3@psf.io> https://hg.python.org/cpython/rev/4d1139976fe3 changeset: 104377:4d1139976fe3 parent: 104374:837114dea493 parent: 104376:f06eb6dd216f user: Serhiy Storchaka date: Sat Oct 08 21:35:07 2016 +0300 summary: Merge from 3.6. files: Lib/_collections_abc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -29,8 +29,8 @@ # so that they will pass tests like: # it = iter(somebytearray) # assert isinstance(it, Iterable) -# Note: in other implementations, these types many not be distinct -# and they make have their own implementation specific types that +# Note: in other implementations, these types might not be distinct +# and they may have their own implementation specific types that # are not included on this list. bytes_iterator = type(iter(b'')) bytearray_iterator = type(iter(bytearray())) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:31 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5=2E?= Message-ID: <20161008190831.17369.54986.7F8029C3@psf.io> https://hg.python.org/cpython/rev/f06eb6dd216f changeset: 104376:f06eb6dd216f branch: 3.6 parent: 104373:4ed634870a9a parent: 104375:ee049edc3fff user: Serhiy Storchaka date: Sat Oct 08 21:34:44 2016 +0300 summary: Merge from 3.5. files: Lib/_collections_abc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -29,8 +29,8 @@ # so that they will pass tests like: # it = iter(somebytearray) # assert isinstance(it, Iterable) -# Note: in other implementations, these types many not be distinct -# and they make have their own implementation specific types that +# Note: in other implementations, these types might not be distinct +# and they may have their own implementation specific types that # are not included on this list. bytes_iterator = type(iter(b'')) bytearray_iterator = type(iter(bytearray())) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:31 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzc2?= =?utf-8?q?=3A_Fixed_typos=2E?= Message-ID: <20161008190831.15207.24187.F1F41F31@psf.io> https://hg.python.org/cpython/rev/ee049edc3fff changeset: 104375:ee049edc3fff branch: 3.5 parent: 104365:bbaf6c928526 user: Serhiy Storchaka date: Sat Oct 08 21:33:59 2016 +0300 summary: Issue #28376: Fixed typos. Based on patch by Oren Milman. files: Lib/_collections_abc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -29,8 +29,8 @@ # so that they will pass tests like: # it = iter(somebytearray) # assert isinstance(it, Iterable) -# Note: in other implementations, these types many not be distinct -# and they make have their own implementation specific types that +# Note: in other implementations, these types might not be distinct +# and they may have their own implementation specific types that # are not included on this list. bytes_iterator = type(iter(b'')) bytearray_iterator = type(iter(bytearray())) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:31 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzc2?= =?utf-8?q?=3A_The_constructor_of_range=5Fiterator_now_checks_that_step_is?= =?utf-8?q?_not_0=2E?= Message-ID: <20161008190831.79613.47347.DC054D6F@psf.io> https://hg.python.org/cpython/rev/e486f3d30e0e changeset: 104378:e486f3d30e0e branch: 3.5 parent: 104375:ee049edc3fff user: Serhiy Storchaka date: Sat Oct 08 21:43:11 2016 +0300 summary: Issue #28376: The constructor of range_iterator now checks that step is not 0. Patch by Oren Milman. files: Lib/test/test_range.py | 29 +++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ Objects/rangeobject.c | 14 +++++++++++--- 3 files changed, 43 insertions(+), 3 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 @@ -493,6 +493,35 @@ test_id = "reversed(range({}, {}, {}))".format(start, end, step) self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + @test.support.cpython_only + def test_range_iterator_invocation(self): + import _testcapi + rangeiter_type = type(iter(range(0))) + + # rangeiter_new doesn't take keyword arguments + with self.assertRaises(TypeError): + rangeiter_type(a=1) + + # rangeiter_new takes exactly 3 arguments + self.assertRaises(TypeError, rangeiter_type) + self.assertRaises(TypeError, rangeiter_type, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1, 1, 1) + + # start, stop and stop must fit in C long + for good_val in [_testcapi.LONG_MAX, _testcapi.LONG_MIN]: + rangeiter_type(good_val, good_val, good_val) + for bad_val in [_testcapi.LONG_MAX + 1, _testcapi.LONG_MIN - 1]: + self.assertRaises(OverflowError, + rangeiter_type, bad_val, 1, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, bad_val, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, 1, bad_val) + + # step mustn't be zero + self.assertRaises(ValueError, rangeiter_type, 1, 1, 0) + def test_slice(self): def check(start, stop, step=None): i = slice(start, stop, step) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28376: The constructor of range_iterator now checks that step is not 0. + Patch by Oren Milman. + - Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -937,12 +937,20 @@ { long start, stop, step; - if (!_PyArg_NoKeywords("rangeiter()", kw)) + if (!_PyArg_NoKeywords("range_iterator()", kw)) { return NULL; + } - if (!PyArg_ParseTuple(args, "lll;rangeiter() requires 3 int arguments", - &start, &stop, &step)) + if (!PyArg_ParseTuple(args, + "lll;range_iterator() requires 3 int arguments", + &start, &stop, &step)) { return NULL; + } + if (step == 0) { + PyErr_SetString(PyExc_ValueError, + "range_iterator() arg 3 must not be zero"); + return NULL; + } return fast_range_iter(start, stop, step); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:32 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5=2E?= Message-ID: <20161008190832.75730.12497.4AD4165D@psf.io> https://hg.python.org/cpython/rev/e02d9ae3fde7 changeset: 104379:e02d9ae3fde7 branch: 3.6 parent: 104376:f06eb6dd216f parent: 104378:e486f3d30e0e user: Serhiy Storchaka date: Sat Oct 08 21:45:07 2016 +0300 summary: Merge from 3.5. files: Lib/test/test_range.py | 30 ++++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ Objects/rangeobject.c | 14 +++++++++++--- 3 files changed, 44 insertions(+), 3 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 @@ -4,6 +4,7 @@ import sys import pickle import itertools +import test.support # pure Python implementations (3 args only), for comparison def pyrange(start, stop, step): @@ -493,6 +494,35 @@ test_id = "reversed(range({}, {}, {}))".format(start, end, step) self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + @test.support.cpython_only + def test_range_iterator_invocation(self): + import _testcapi + rangeiter_type = type(iter(range(0))) + + # rangeiter_new doesn't take keyword arguments + with self.assertRaises(TypeError): + rangeiter_type(a=1) + + # rangeiter_new takes exactly 3 arguments + self.assertRaises(TypeError, rangeiter_type) + self.assertRaises(TypeError, rangeiter_type, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1, 1, 1) + + # start, stop and stop must fit in C long + for good_val in [_testcapi.LONG_MAX, _testcapi.LONG_MIN]: + rangeiter_type(good_val, good_val, good_val) + for bad_val in [_testcapi.LONG_MAX + 1, _testcapi.LONG_MIN - 1]: + self.assertRaises(OverflowError, + rangeiter_type, bad_val, 1, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, bad_val, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, 1, bad_val) + + # step mustn't be zero + self.assertRaises(ValueError, rangeiter_type, 1, 1, 0) + def test_slice(self): def check(start, stop, step=None): i = slice(start, stop, step) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28376: The constructor of range_iterator now checks that step is not 0. + Patch by Oren Milman. + - Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -930,12 +930,20 @@ { long start, stop, step; - if (!_PyArg_NoKeywords("rangeiter()", kw)) + if (!_PyArg_NoKeywords("range_iterator()", kw)) { return NULL; + } - if (!PyArg_ParseTuple(args, "lll;rangeiter() requires 3 int arguments", - &start, &stop, &step)) + if (!PyArg_ParseTuple(args, + "lll;range_iterator() requires 3 int arguments", + &start, &stop, &step)) { return NULL; + } + if (step == 0) { + PyErr_SetString(PyExc_ValueError, + "range_iterator() arg 3 must not be zero"); + return NULL; + } return fast_range_iter(start, stop, step); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:32 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4Mzc2?= =?utf-8?q?=3A_Creating_instances_of_range=5Fiterator_by_calling_range=5Fi?= =?utf-8?q?terator?= Message-ID: <20161008190832.82319.5816.4316E66C@psf.io> https://hg.python.org/cpython/rev/06f065a59751 changeset: 104380:06f065a59751 branch: 3.6 user: Serhiy Storchaka date: Sat Oct 08 21:50:45 2016 +0300 summary: Issue #28376: Creating instances of range_iterator by calling range_iterator type now is deprecated. Patch by Oren Milman. files: Lib/test/test_range.py | 43 ++++++++++++++++------------- Misc/NEWS | 3 ++ Objects/rangeobject.c | 7 ++++ 3 files changed, 33 insertions(+), 20 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 @@ -499,29 +499,32 @@ import _testcapi rangeiter_type = type(iter(range(0))) - # rangeiter_new doesn't take keyword arguments - with self.assertRaises(TypeError): - rangeiter_type(a=1) + self.assertWarns(DeprecationWarning, rangeiter_type, 1, 3, 1) - # rangeiter_new takes exactly 3 arguments - self.assertRaises(TypeError, rangeiter_type) - self.assertRaises(TypeError, rangeiter_type, 1) - self.assertRaises(TypeError, rangeiter_type, 1, 1) - self.assertRaises(TypeError, rangeiter_type, 1, 1, 1, 1) + with test.support.check_warnings(('', DeprecationWarning)): + # rangeiter_new doesn't take keyword arguments + with self.assertRaises(TypeError): + rangeiter_type(a=1) - # start, stop and stop must fit in C long - for good_val in [_testcapi.LONG_MAX, _testcapi.LONG_MIN]: - rangeiter_type(good_val, good_val, good_val) - for bad_val in [_testcapi.LONG_MAX + 1, _testcapi.LONG_MIN - 1]: - self.assertRaises(OverflowError, - rangeiter_type, bad_val, 1, 1) - self.assertRaises(OverflowError, - rangeiter_type, 1, bad_val, 1) - self.assertRaises(OverflowError, - rangeiter_type, 1, 1, bad_val) + # rangeiter_new takes exactly 3 arguments + self.assertRaises(TypeError, rangeiter_type) + self.assertRaises(TypeError, rangeiter_type, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1, 1, 1) - # step mustn't be zero - self.assertRaises(ValueError, rangeiter_type, 1, 1, 0) + # start, stop and stop must fit in C long + for good_val in [_testcapi.LONG_MAX, _testcapi.LONG_MIN]: + rangeiter_type(good_val, good_val, good_val) + for bad_val in [_testcapi.LONG_MAX + 1, _testcapi.LONG_MIN - 1]: + self.assertRaises(OverflowError, + rangeiter_type, bad_val, 1, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, bad_val, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, 1, bad_val) + + # step mustn't be zero + self.assertRaises(ValueError, rangeiter_type, 1, 1, 0) def test_slice(self): def check(start, stop, step=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28376: Creating instances of range_iterator by calling range_iterator + type now is deprecated. Patch by Oren Milman. + - Issue #28376: The constructor of range_iterator now checks that step is not 0. Patch by Oren Milman. diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -930,6 +930,13 @@ { long start, stop, step; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "range_iterator(): creating instances of range_iterator " + "by calling range_iterator type is deprecated", + 1)) { + return NULL; + } + if (!_PyArg_NoKeywords("range_iterator()", kw)) { return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:32 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:32 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2Ugd2l0aCAzLjYu?= Message-ID: <20161008190832.82059.94268.790817D5@psf.io> https://hg.python.org/cpython/rev/a12d3b533002 changeset: 104381:a12d3b533002 parent: 104377:4d1139976fe3 parent: 104380:06f065a59751 user: Serhiy Storchaka date: Sat Oct 08 21:52:41 2016 +0300 summary: Merge with 3.6. files: Lib/test/test_range.py | 33 ++++++++++++++++++++++++++++++ Misc/NEWS | 6 +++++ Objects/rangeobject.c | 21 ++++++++++++++++-- 3 files changed, 57 insertions(+), 3 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 @@ -4,6 +4,7 @@ import sys import pickle import itertools +import test.support # pure Python implementations (3 args only), for comparison def pyrange(start, stop, step): @@ -493,6 +494,38 @@ test_id = "reversed(range({}, {}, {}))".format(start, end, step) self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + @test.support.cpython_only + def test_range_iterator_invocation(self): + import _testcapi + rangeiter_type = type(iter(range(0))) + + self.assertWarns(DeprecationWarning, rangeiter_type, 1, 3, 1) + + with test.support.check_warnings(('', DeprecationWarning)): + # rangeiter_new doesn't take keyword arguments + with self.assertRaises(TypeError): + rangeiter_type(a=1) + + # rangeiter_new takes exactly 3 arguments + self.assertRaises(TypeError, rangeiter_type) + self.assertRaises(TypeError, rangeiter_type, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1) + self.assertRaises(TypeError, rangeiter_type, 1, 1, 1, 1) + + # start, stop and stop must fit in C long + for good_val in [_testcapi.LONG_MAX, _testcapi.LONG_MIN]: + rangeiter_type(good_val, good_val, good_val) + for bad_val in [_testcapi.LONG_MAX + 1, _testcapi.LONG_MIN - 1]: + self.assertRaises(OverflowError, + rangeiter_type, bad_val, 1, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, bad_val, 1) + self.assertRaises(OverflowError, + rangeiter_type, 1, 1, bad_val) + + # step mustn't be zero + self.assertRaises(ValueError, rangeiter_type, 1, 1, 0) + def test_slice(self): def check(start, stop, step=None): i = slice(start, stop, step) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,12 @@ Core and Builtins ----------------- +- Issue #28376: Creating instances of range_iterator by calling range_iterator + type now is deprecated. Patch by Oren Milman. + +- Issue #28376: The constructor of range_iterator now checks that step is not 0. + Patch by Oren Milman. + - Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -930,12 +930,27 @@ { long start, stop, step; - if (!_PyArg_NoKeywords("rangeiter()", kw)) + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "range_iterator(): creating instances of range_iterator " + "by calling range_iterator type is deprecated", + 1)) { return NULL; + } - if (!PyArg_ParseTuple(args, "lll;rangeiter() requires 3 int arguments", - &start, &stop, &step)) + if (!_PyArg_NoKeywords("range_iterator()", kw)) { return NULL; + } + + if (!PyArg_ParseTuple(args, + "lll;range_iterator() requires 3 int arguments", + &start, &stop, &step)) { + return NULL; + } + if (step == 0) { + PyErr_SetString(PyExc_ValueError, + "range_iterator() arg 3 must not be zero"); + return NULL; + } return fast_range_iter(start, stop, step); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328376=3A_Creating?= =?utf-8?q?_instances_of_range=5Fiterator_by_calling_range=5Fiterator?= Message-ID: <20161008190832.94878.78310.E2B3AB1B@psf.io> https://hg.python.org/cpython/rev/e099583400f3 changeset: 104382:e099583400f3 user: Serhiy Storchaka date: Sat Oct 08 22:01:18 2016 +0300 summary: Issue #28376: Creating instances of range_iterator by calling range_iterator type now is disallowed. Calling iter() on range instance is the only way. Patch by Oren Milman. files: Lib/test/test_range.py | 37 ++++---------------------- Misc/NEWS | 4 +-- Objects/rangeobject.c | 41 ------------------------------ 3 files changed, 7 insertions(+), 75 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 @@ -4,7 +4,6 @@ import sys import pickle import itertools -import test.support # pure Python implementations (3 args only), for comparison def pyrange(start, stop, step): @@ -494,37 +493,13 @@ test_id = "reversed(range({}, {}, {}))".format(start, end, step) self.assert_iterators_equal(iter1, iter2, test_id, limit=100) - @test.support.cpython_only - def test_range_iterator_invocation(self): - import _testcapi + def test_range_iterators_invocation(self): + # verify range iterators instances cannot be created by + # calling their type rangeiter_type = type(iter(range(0))) - - self.assertWarns(DeprecationWarning, rangeiter_type, 1, 3, 1) - - with test.support.check_warnings(('', DeprecationWarning)): - # rangeiter_new doesn't take keyword arguments - with self.assertRaises(TypeError): - rangeiter_type(a=1) - - # rangeiter_new takes exactly 3 arguments - self.assertRaises(TypeError, rangeiter_type) - self.assertRaises(TypeError, rangeiter_type, 1) - self.assertRaises(TypeError, rangeiter_type, 1, 1) - self.assertRaises(TypeError, rangeiter_type, 1, 1, 1, 1) - - # start, stop and stop must fit in C long - for good_val in [_testcapi.LONG_MAX, _testcapi.LONG_MIN]: - rangeiter_type(good_val, good_val, good_val) - for bad_val in [_testcapi.LONG_MAX + 1, _testcapi.LONG_MIN - 1]: - self.assertRaises(OverflowError, - rangeiter_type, bad_val, 1, 1) - self.assertRaises(OverflowError, - rangeiter_type, 1, bad_val, 1) - self.assertRaises(OverflowError, - rangeiter_type, 1, 1, bad_val) - - # step mustn't be zero - self.assertRaises(ValueError, rangeiter_type, 1, 1, 0) + self.assertRaises(TypeError, rangeiter_type, 1, 3, 1) + long_rangeiter_type = type(iter(range(1 << 1000))) + self.assertRaises(TypeError, long_rangeiter_type, 1, 3, 1) def test_slice(self): def check(start, stop, step=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,9 +11,7 @@ ----------------- - Issue #28376: Creating instances of range_iterator by calling range_iterator - type now is deprecated. Patch by Oren Milman. - -- Issue #28376: The constructor of range_iterator now checks that step is not 0. + type now is disallowed. Calling iter() on range instance is the only way. Patch by Oren Milman. - Issue #26906: Resolving special methods of uninitialized type now causes diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -829,8 +829,6 @@ {NULL, NULL} /* sentinel */ }; -static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); - PyTypeObject PyRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "range_iterator", /* tp_name */ @@ -862,15 +860,6 @@ (iternextfunc)rangeiter_next, /* tp_iternext */ rangeiter_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - rangeiter_new, /* tp_new */ }; /* Return number of items in range (lo, hi, step). step != 0 @@ -925,36 +914,6 @@ return (PyObject *)it; } -static PyObject * -rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kw) -{ - long start, stop, step; - - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "range_iterator(): creating instances of range_iterator " - "by calling range_iterator type is deprecated", - 1)) { - return NULL; - } - - if (!_PyArg_NoKeywords("range_iterator()", kw)) { - return NULL; - } - - if (!PyArg_ParseTuple(args, - "lll;range_iterator() requires 3 int arguments", - &start, &stop, &step)) { - return NULL; - } - if (step == 0) { - PyErr_SetString(PyExc_ValueError, - "range_iterator() arg 3 must not be zero"); - return NULL; - } - - return fast_range_iter(start, stop, step); -} - typedef struct { PyObject_HEAD PyObject *index; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5=2E?= Message-ID: <20161008190833.1540.52212.60175EF1@psf.io> https://hg.python.org/cpython/rev/e6ec01903f6c changeset: 104384:e6ec01903f6c branch: 3.6 parent: 104380:06f065a59751 parent: 104383:ce4af7593e45 user: Serhiy Storchaka date: Sat Oct 08 22:06:52 2016 +0300 summary: Merge from 3.5. files: Lib/_collections_abc.py | 2 ++ Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -41,6 +41,7 @@ list_iterator = type(iter([])) list_reverseiterator = type(iter(reversed([]))) range_iterator = type(iter(range(0))) +longrange_iterator = type(iter(range(1 << 1000))) set_iterator = type(iter(set())) str_iterator = type(iter("")) tuple_iterator = type(iter(())) @@ -225,6 +226,7 @@ Iterator.register(list_iterator) Iterator.register(list_reverseiterator) Iterator.register(range_iterator) +Iterator.register(longrange_iterator) Iterator.register(set_iterator) Iterator.register(str_iterator) Iterator.register(tuple_iterator) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28376: The type of long range iterator is now registered as Iterator. + Patch by Oren Milman. + - Issue #28376: Creating instances of range_iterator by calling range_iterator type now is deprecated. Patch by Oren Milman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzc2?= =?utf-8?q?=3A_The_type_of_long_range_iterator_is_now_registered_as_Iterat?= =?utf-8?b?b3Iu?= Message-ID: <20161008190833.95317.65791.76AC3BAA@psf.io> https://hg.python.org/cpython/rev/ce4af7593e45 changeset: 104383:ce4af7593e45 branch: 3.5 parent: 104378:e486f3d30e0e user: Serhiy Storchaka date: Sat Oct 08 22:04:12 2016 +0300 summary: Issue #28376: The type of long range iterator is now registered as Iterator. Patch by Oren Milman. files: Lib/_collections_abc.py | 2 ++ Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -41,6 +41,7 @@ list_iterator = type(iter([])) list_reverseiterator = type(iter(reversed([]))) range_iterator = type(iter(range(0))) +longrange_iterator = type(iter(range(1 << 1000))) set_iterator = type(iter(set())) str_iterator = type(iter("")) tuple_iterator = type(iter(())) @@ -234,6 +235,7 @@ Iterator.register(list_iterator) Iterator.register(list_reverseiterator) Iterator.register(range_iterator) +Iterator.register(longrange_iterator) Iterator.register(set_iterator) Iterator.register(str_iterator) Iterator.register(tuple_iterator) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28376: The type of long range iterator is now registered as Iterator. + Patch by Oren Milman. + - Issue #28376: The constructor of range_iterator now checks that step is not 0. Patch by Oren Milman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:08:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:08:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjYu?= Message-ID: <20161008190833.5324.11748.B986BB4C@psf.io> https://hg.python.org/cpython/rev/e3f044acb65a changeset: 104385:e3f044acb65a parent: 104382:e099583400f3 parent: 104384:e6ec01903f6c user: Serhiy Storchaka date: Sat Oct 08 22:07:45 2016 +0300 summary: Merge from 3.6. files: Lib/_collections_abc.py | 2 ++ Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -41,6 +41,7 @@ list_iterator = type(iter([])) list_reverseiterator = type(iter(reversed([]))) range_iterator = type(iter(range(0))) +longrange_iterator = type(iter(range(1 << 1000))) set_iterator = type(iter(set())) str_iterator = type(iter("")) tuple_iterator = type(iter(())) @@ -225,6 +226,7 @@ Iterator.register(list_iterator) Iterator.register(list_reverseiterator) Iterator.register(range_iterator) +Iterator.register(longrange_iterator) Iterator.register(set_iterator) Iterator.register(str_iterator) Iterator.register(tuple_iterator) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28376: The type of long range iterator is now registered as Iterator. + Patch by Oren Milman. + - Issue #28376: Creating instances of range_iterator by calling range_iterator type now is disallowed. Calling iter() on range instance is the only way. Patch by Oren Milman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:18:59 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:18:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328333=3A_Enables_Unicode_for_ps1/ps2_and_input?= =?utf-8?q?=28=29_prompts=2E_=28Patch_by_Eryk?= Message-ID: <20161008191859.79510.71071.8D132318@psf.io> https://hg.python.org/cpython/rev/cb62e921bd06 changeset: 104387:cb62e921bd06 parent: 104385:e3f044acb65a parent: 104386:faf5493e6f61 user: Steve Dower date: Sat Oct 08 12:18:28 2016 -0700 summary: Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by Eryk Sun) files: Misc/NEWS | 2 ++ Parser/myreadline.c | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -222,6 +222,8 @@ Windows ------- +- Issue #28333: Enables Unicode for ps1/ps2 and input() prompts + - Issue #28251: Improvements to help manuals on Windows. - Issue #28110: launcher.msi has different product codes between 32-bit and diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -203,17 +203,37 @@ #ifdef MS_WINDOWS if (!Py_LegacyWindowsStdioFlag && sys_stdin == stdin) { - HANDLE hStdIn; + HANDLE hStdIn, hStdErr; _Py_BEGIN_SUPPRESS_IPH hStdIn = (HANDLE)_get_osfhandle(fileno(sys_stdin)); + hStdErr = (HANDLE)_get_osfhandle(fileno(stderr)); _Py_END_SUPPRESS_IPH if (_get_console_type(hStdIn) == 'r') { fflush(sys_stdout); - if (prompt) - fprintf(stderr, "%s", prompt); - fflush(stderr); + if (prompt) { + if (_get_console_type(hStdErr) == 'w') { + wchar_t *wbuf; + int wlen; + wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, + NULL, 0); + if (wlen++ && + (wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)))) { + wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, + wbuf, wlen); + if (wlen) { + DWORD n; + fflush(stderr); + WriteConsoleW(hStdErr, wbuf, wlen, &n, NULL); + } + PyMem_RawFree(wbuf); + } + } else { + fprintf(stderr, "%s", prompt); + fflush(stderr); + } + } clearerr(sys_stdin); return _PyOS_WindowsConsoleReadline(hStdIn); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:18:58 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:18:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzMz?= =?utf-8?q?=3A_Enables_Unicode_for_ps1/ps2_and_input=28=29_prompts=2E_=28P?= =?utf-8?q?atch_by_Eryk?= Message-ID: <20161008191858.1375.43272.0B4829D0@psf.io> https://hg.python.org/cpython/rev/faf5493e6f61 changeset: 104386:faf5493e6f61 branch: 3.6 parent: 104384:e6ec01903f6c user: Steve Dower date: Sat Oct 08 12:18:16 2016 -0700 summary: Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by Eryk Sun) files: Misc/NEWS | 2 ++ Parser/myreadline.c | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -213,6 +213,8 @@ Windows ------- +- Issue #28333: Enables Unicode for ps1/ps2 and input() prompts + - Issue #28251: Improvements to help manuals on Windows. - Issue #28110: launcher.msi has different product codes between 32-bit and diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -203,17 +203,37 @@ #ifdef MS_WINDOWS if (!Py_LegacyWindowsStdioFlag && sys_stdin == stdin) { - HANDLE hStdIn; + HANDLE hStdIn, hStdErr; _Py_BEGIN_SUPPRESS_IPH hStdIn = (HANDLE)_get_osfhandle(fileno(sys_stdin)); + hStdErr = (HANDLE)_get_osfhandle(fileno(stderr)); _Py_END_SUPPRESS_IPH if (_get_console_type(hStdIn) == 'r') { fflush(sys_stdout); - if (prompt) - fprintf(stderr, "%s", prompt); - fflush(stderr); + if (prompt) { + if (_get_console_type(hStdErr) == 'w') { + wchar_t *wbuf; + int wlen; + wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, + NULL, 0); + if (wlen++ && + (wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)))) { + wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, + wbuf, wlen); + if (wlen) { + DWORD n; + fflush(stderr); + WriteConsoleW(hStdErr, wbuf, wlen, &n, NULL); + } + PyMem_RawFree(wbuf); + } + } else { + fprintf(stderr, "%s", prompt); + fflush(stderr); + } + } clearerr(sys_stdin); return _PyOS_WindowsConsoleReadline(hStdIn); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:21:32 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:21:32 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328333=3A_Remove_unnecessary_increment=2E?= Message-ID: <20161008192132.20805.69523.A8D5EA79@psf.io> https://hg.python.org/cpython/rev/d76c8f9ea787 changeset: 104389:d76c8f9ea787 parent: 104387:cb62e921bd06 parent: 104388:63ceadf8410f user: Steve Dower date: Sat Oct 08 12:21:00 2016 -0700 summary: Issue #28333: Remove unnecessary increment. files: Parser/myreadline.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -218,7 +218,7 @@ int wlen; wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, NULL, 0); - if (wlen++ && + if (wlen && (wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)))) { wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, wbuf, wlen); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:21:32 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:21:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzMz?= =?utf-8?q?=3A_Remove_unnecessary_increment=2E?= Message-ID: <20161008192132.75771.41483.A6D12471@psf.io> https://hg.python.org/cpython/rev/63ceadf8410f changeset: 104388:63ceadf8410f branch: 3.6 parent: 104386:faf5493e6f61 user: Steve Dower date: Sat Oct 08 12:20:45 2016 -0700 summary: Issue #28333: Remove unnecessary increment. files: Parser/myreadline.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -218,7 +218,7 @@ int wlen; wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, NULL, 0); - if (wlen++ && + if (wlen && (wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)))) { wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, wbuf, wlen); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:24:46 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:24:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Add_proper_cre?= =?utf-8?q?dit_to_NEWS_file=2E?= Message-ID: <20161008192446.79751.81379.B08D5255@psf.io> https://hg.python.org/cpython/rev/701e52103528 changeset: 104390:701e52103528 branch: 3.6 parent: 104388:63ceadf8410f user: Steve Dower date: Sat Oct 08 12:24:30 2016 -0700 summary: Add proper credit to NEWS file. files: Misc/NEWS | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -213,7 +213,8 @@ Windows ------- -- Issue #28333: Enables Unicode for ps1/ps2 and input() prompts +- Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by + Eryk Sun) - Issue #28251: Improvements to help manuals on Windows. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:24:46 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:24:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E6?= Message-ID: <20161008192446.21011.71481.7E4678B8@psf.io> https://hg.python.org/cpython/rev/1af036b2dc01 changeset: 104391:1af036b2dc01 parent: 104389:d76c8f9ea787 parent: 104390:701e52103528 user: Steve Dower date: Sat Oct 08 12:24:37 2016 -0700 summary: Merge with 3.6 files: Misc/NEWS | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -222,7 +222,8 @@ Windows ------- -- Issue #28333: Enables Unicode for ps1/ps2 and input() prompts +- Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by + Eryk Sun) - Issue #28251: Improvements to help manuals on Windows. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:38:05 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:38:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328162=3A_Fixes_Ctrl+Z_handling_in_console_reada?= =?utf-8?q?ll=28=29?= Message-ID: <20161008193805.85745.51150.4EBF557F@psf.io> https://hg.python.org/cpython/rev/947fa496ca6f changeset: 104393:947fa496ca6f parent: 104391:1af036b2dc01 parent: 104392:4d4aefa52f49 user: Steve Dower date: Sat Oct 08 12:37:57 2016 -0700 summary: Issue #28162: Fixes Ctrl+Z handling in console readall() files: Lib/test/test_winconsoleio.py | 42 +++++++++++-------- Modules/_io/winconsoleio.c | 49 +++++++++++++--------- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py --- a/Lib/test/test_winconsoleio.py +++ b/Lib/test/test_winconsoleio.py @@ -107,16 +107,15 @@ source = '??????\r\n'.encode('utf-16-le') expected = '??????\r\n'.encode('utf-8') for read_count in range(1, 16): - stdin = open('CONIN$', 'rb', buffering=0) - write_input(stdin, source) + with open('CONIN$', 'rb', buffering=0) as stdin: + write_input(stdin, source) - actual = b'' - while not actual.endswith(b'\n'): - b = stdin.read(read_count) - actual += b + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b - self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) - stdin.close() + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) def test_partial_surrogate_reads(self): # Test that reading less than 1 full character works when stdin @@ -125,17 +124,24 @@ source = '\U00101FFF\U00101001\r\n'.encode('utf-16-le') expected = '\U00101FFF\U00101001\r\n'.encode('utf-8') for read_count in range(1, 16): - stdin = open('CONIN$', 'rb', buffering=0) + with open('CONIN$', 'rb', buffering=0) as stdin: + write_input(stdin, source) + + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b + + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) + + def test_ctrl_z(self): + with open('CONIN$', 'rb', buffering=0) as stdin: + source = '\xC4\x1A\r\n'.encode('utf-16-le') + expected = '\xC4'.encode('utf-8') write_input(stdin, source) - - actual = b'' - while not actual.endswith(b'\n'): - b = stdin.read(read_count) - actual += b - - self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) - stdin.close() - + a, b = stdin.read(1), stdin.readall() + self.assertEqual(expected[0:1], a) + self.assertEqual(expected[1:], b) if __name__ == "__main__": unittest.main() diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -816,44 +816,53 @@ PyMem_Free(subbuf); - /* when the read starts with ^Z or is empty we break */ - if (n == 0 || buf[len] == '\x1a') + /* when the read is empty we break */ + if (n == 0) break; len += n; } - if (len == 0 || buf[0] == '\x1a' && _buflen(self) == 0) { + if (len == 0 && _buflen(self) == 0) { /* when the result starts with ^Z we return an empty buffer */ PyMem_Free(buf); return PyBytes_FromStringAndSize(NULL, 0); } - Py_BEGIN_ALLOW_THREADS - bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, - NULL, 0, NULL, NULL); - Py_END_ALLOW_THREADS + if (len) { + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + NULL, 0, NULL, NULL); + Py_END_ALLOW_THREADS - if (!bytes_size) { - DWORD err = GetLastError(); - PyMem_Free(buf); - return PyErr_SetFromWindowsErr(err); + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + return PyErr_SetFromWindowsErr(err); + } + } else { + bytes_size = 0; } bytes_size += _buflen(self); bytes = PyBytes_FromStringAndSize(NULL, bytes_size); rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size); - Py_BEGIN_ALLOW_THREADS - bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, - &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); - Py_END_ALLOW_THREADS + if (len) { + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); + Py_END_ALLOW_THREADS - if (!bytes_size) { - DWORD err = GetLastError(); - PyMem_Free(buf); - Py_CLEAR(bytes); - return PyErr_SetFromWindowsErr(err); + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + Py_CLEAR(bytes); + return PyErr_SetFromWindowsErr(err); + } + + /* add back the number of preserved bytes */ + bytes_size += rn; } PyMem_Free(buf); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:38:05 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 08 Oct 2016 19:38:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MTYy?= =?utf-8?q?=3A_Fixes_Ctrl+Z_handling_in_console_readall=28=29?= Message-ID: <20161008193805.20734.53544.3DF20A45@psf.io> https://hg.python.org/cpython/rev/4d4aefa52f49 changeset: 104392:4d4aefa52f49 branch: 3.6 parent: 104390:701e52103528 user: Steve Dower date: Sat Oct 08 12:37:33 2016 -0700 summary: Issue #28162: Fixes Ctrl+Z handling in console readall() files: Lib/test/test_winconsoleio.py | 42 +++++++++++-------- Modules/_io/winconsoleio.c | 49 +++++++++++++--------- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py --- a/Lib/test/test_winconsoleio.py +++ b/Lib/test/test_winconsoleio.py @@ -107,16 +107,15 @@ source = '??????\r\n'.encode('utf-16-le') expected = '??????\r\n'.encode('utf-8') for read_count in range(1, 16): - stdin = open('CONIN$', 'rb', buffering=0) - write_input(stdin, source) + with open('CONIN$', 'rb', buffering=0) as stdin: + write_input(stdin, source) - actual = b'' - while not actual.endswith(b'\n'): - b = stdin.read(read_count) - actual += b + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b - self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) - stdin.close() + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) def test_partial_surrogate_reads(self): # Test that reading less than 1 full character works when stdin @@ -125,17 +124,24 @@ source = '\U00101FFF\U00101001\r\n'.encode('utf-16-le') expected = '\U00101FFF\U00101001\r\n'.encode('utf-8') for read_count in range(1, 16): - stdin = open('CONIN$', 'rb', buffering=0) + with open('CONIN$', 'rb', buffering=0) as stdin: + write_input(stdin, source) + + actual = b'' + while not actual.endswith(b'\n'): + b = stdin.read(read_count) + actual += b + + self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) + + def test_ctrl_z(self): + with open('CONIN$', 'rb', buffering=0) as stdin: + source = '\xC4\x1A\r\n'.encode('utf-16-le') + expected = '\xC4'.encode('utf-8') write_input(stdin, source) - - actual = b'' - while not actual.endswith(b'\n'): - b = stdin.read(read_count) - actual += b - - self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count)) - stdin.close() - + a, b = stdin.read(1), stdin.readall() + self.assertEqual(expected[0:1], a) + self.assertEqual(expected[1:], b) if __name__ == "__main__": unittest.main() diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -816,44 +816,53 @@ PyMem_Free(subbuf); - /* when the read starts with ^Z or is empty we break */ - if (n == 0 || buf[len] == '\x1a') + /* when the read is empty we break */ + if (n == 0) break; len += n; } - if (len == 0 || buf[0] == '\x1a' && _buflen(self) == 0) { + if (len == 0 && _buflen(self) == 0) { /* when the result starts with ^Z we return an empty buffer */ PyMem_Free(buf); return PyBytes_FromStringAndSize(NULL, 0); } - Py_BEGIN_ALLOW_THREADS - bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, - NULL, 0, NULL, NULL); - Py_END_ALLOW_THREADS + if (len) { + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + NULL, 0, NULL, NULL); + Py_END_ALLOW_THREADS - if (!bytes_size) { - DWORD err = GetLastError(); - PyMem_Free(buf); - return PyErr_SetFromWindowsErr(err); + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + return PyErr_SetFromWindowsErr(err); + } + } else { + bytes_size = 0; } bytes_size += _buflen(self); bytes = PyBytes_FromStringAndSize(NULL, bytes_size); rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size); - Py_BEGIN_ALLOW_THREADS - bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, - &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); - Py_END_ALLOW_THREADS + if (len) { + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); + Py_END_ALLOW_THREADS - if (!bytes_size) { - DWORD err = GetLastError(); - PyMem_Free(buf); - Py_CLEAR(bytes); - return PyErr_SetFromWindowsErr(err); + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + Py_CLEAR(bytes); + return PyErr_SetFromWindowsErr(err); + } + + /* add back the number of preserved bytes */ + bytes_size += rn; } PyMem_Free(buf); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:48:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:48:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzc5?= =?utf-8?q?=3A_Added_sanity_checks_and_tests_for_PyUnicode=5FCopyCharacter?= =?utf-8?b?cygpLg==?= Message-ID: <20161008194828.1375.69028.2021F7AC@psf.io> https://hg.python.org/cpython/rev/13addd71b751 changeset: 104394:13addd71b751 branch: 3.5 parent: 104383:ce4af7593e45 user: Serhiy Storchaka date: Sat Oct 08 22:45:38 2016 +0300 summary: Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). Patch by Xiang Zhang. files: Doc/c-api/unicode.rst | 9 +++- Lib/test/test_unicode.py | 45 ++++++++++++++++++++++++++- Misc/NEWS | 3 + Modules/_testcapimodule.c | 34 ++++++++++++++++++++ Objects/unicodeobject.c | 10 ++++- 5 files changed, 94 insertions(+), 7 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 @@ -578,13 +578,16 @@ .. versionadded:: 3.3 -.. c:function:: int PyUnicode_CopyCharacters(PyObject *to, Py_ssize_t to_start, \ - PyObject *from, Py_ssize_t from_start, Py_ssize_t how_many) +.. c:function:: Py_ssize_t PyUnicode_CopyCharacters(PyObject *to, \ + Py_ssize_t to_start, \ + PyObject *from, \ + Py_ssize_t from_start, \ + Py_ssize_t how_many) Copy characters from one Unicode object into another. This function performs character conversion when necessary and falls back to :c:func:`memcpy` if possible. Returns ``-1`` and sets an exception on error, otherwise returns - ``0``. + the number of copied characters. .. versionadded:: 3.3 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 @@ -4,7 +4,7 @@ (c) Copyright CNRI, All Rights Reserved. NO WARRANTY. -"""#" +""" import _string import codecs import itertools @@ -2704,6 +2704,49 @@ self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + # Test PyUnicode_CopyCharacters() + @support.cpython_only + def test_copycharacters(self): + from _testcapi import unicode_copycharacters + + strings = [ + 'abcde', '\xa1\xa2\xa3\xa4\xa5', + '\u4f60\u597d\u4e16\u754c\uff01', + '\U0001f600\U0001f601\U0001f602\U0001f603\U0001f604' + ] + + for idx, from_ in enumerate(strings): + # wide -> narrow: exceed maxchar limitation + for to in strings[:idx]: + self.assertRaises( + SystemError, + unicode_copycharacters, to, 0, from_, 0, 5 + ) + # same kind + for from_start in range(5): + self.assertEqual( + unicode_copycharacters(from_, 0, from_, from_start, 5), + (from_[from_start:from_start+5].ljust(5, '\0'), + 5-from_start) + ) + for to_start in range(5): + self.assertEqual( + unicode_copycharacters(from_, to_start, from_, to_start, 5), + (from_[to_start:to_start+5].rjust(5, '\0'), + 5-to_start) + ) + # narrow -> wide + # Tests omitted since this creates invalid strings. + + s = strings[0] + self.assertRaises(IndexError, unicode_copycharacters, s, 6, s, 0, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, -1, s, 0, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, 6, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, -1, 5) + self.assertRaises(SystemError, unicode_copycharacters, s, 1, s, 0, 5) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, s, 0, -1) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, b'', 0, 0) + @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). + Patch by Xiang Zhang. + - Issue #28376: The type of long range iterator is now registered as Iterator. Patch by Oren Milman. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1860,6 +1860,39 @@ } static PyObject * +unicode_copycharacters(PyObject *self, PyObject *args) +{ + PyObject *from, *to, *to_copy; + Py_ssize_t from_start, to_start, how_many, copied; + + if (!PyArg_ParseTuple(args, "UnOnn:unicode_copycharacters", &to, &to_start, + &from, &from_start, &how_many)) { + return NULL; + } + + if (PyUnicode_READY(to) < 0) { + return NULL; + } + + if (!(to_copy = PyUnicode_New(PyUnicode_GET_LENGTH(to), + PyUnicode_MAX_CHAR_VALUE(to)))) { + return NULL; + } + if (PyUnicode_Fill(to_copy, 0, PyUnicode_GET_LENGTH(to_copy), 0U) < 0) { + Py_DECREF(to_copy); + return NULL; + } + + if ((copied = PyUnicode_CopyCharacters(to_copy, to_start, from, + from_start, how_many)) < 0) { + Py_DECREF(to_copy); + return NULL; + } + + return Py_BuildValue("(Nn)", to_copy, copied); +} + +static PyObject * unicode_encodedecimal(PyObject *self, PyObject *args) { Py_UNICODE *unicode; @@ -3915,6 +3948,7 @@ {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, {"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS}, {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, + {"unicode_copycharacters", unicode_copycharacters, METH_VARARGS}, {"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS}, {"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS}, {"unicode_legacy_string", unicode_legacy_string, METH_VARARGS}, diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1366,15 +1366,19 @@ if (PyUnicode_READY(to) == -1) return -1; - if (from_start < 0) { + if ((size_t)from_start > (size_t)PyUnicode_GET_LENGTH(from)) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } - if (to_start < 0) { + if ((size_t)to_start > (size_t)PyUnicode_GET_LENGTH(to)) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } - how_many = Py_MIN(PyUnicode_GET_LENGTH(from), how_many); + if (how_many < 0) { + PyErr_SetString(PyExc_SystemError, "how_many cannot be negative"); + return -1; + } + how_many = Py_MIN(PyUnicode_GET_LENGTH(from)-from_start, how_many); if (to_start + how_many > PyUnicode_GET_LENGTH(to)) { PyErr_Format(PyExc_SystemError, "Cannot write %zi characters at %zi " -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:48:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:48:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5=2E?= Message-ID: <20161008194828.5245.79170.48962013@psf.io> https://hg.python.org/cpython/rev/6803a6478056 changeset: 104395:6803a6478056 branch: 3.6 parent: 104392:4d4aefa52f49 parent: 104394:13addd71b751 user: Serhiy Storchaka date: Sat Oct 08 22:46:01 2016 +0300 summary: Merge from 3.5. files: Doc/c-api/unicode.rst | 9 +++- Lib/test/test_unicode.py | 45 ++++++++++++++++++++++++++- Misc/NEWS | 3 + Modules/_testcapimodule.c | 34 ++++++++++++++++++++ Objects/unicodeobject.c | 10 ++++- 5 files changed, 94 insertions(+), 7 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 @@ -572,13 +572,16 @@ .. versionadded:: 3.3 -.. c:function:: int PyUnicode_CopyCharacters(PyObject *to, Py_ssize_t to_start, \ - PyObject *from, Py_ssize_t from_start, Py_ssize_t how_many) +.. c:function:: Py_ssize_t PyUnicode_CopyCharacters(PyObject *to, \ + Py_ssize_t to_start, \ + PyObject *from, \ + Py_ssize_t from_start, \ + Py_ssize_t how_many) Copy characters from one Unicode object into another. This function performs character conversion when necessary and falls back to :c:func:`memcpy` if possible. Returns ``-1`` and sets an exception on error, otherwise returns - ``0``. + the number of copied characters. .. versionadded:: 3.3 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 @@ -4,7 +4,7 @@ (c) Copyright CNRI, All Rights Reserved. NO WARRANTY. -"""#" +""" import _string import codecs import itertools @@ -2735,6 +2735,49 @@ self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + # Test PyUnicode_CopyCharacters() + @support.cpython_only + def test_copycharacters(self): + from _testcapi import unicode_copycharacters + + strings = [ + 'abcde', '\xa1\xa2\xa3\xa4\xa5', + '\u4f60\u597d\u4e16\u754c\uff01', + '\U0001f600\U0001f601\U0001f602\U0001f603\U0001f604' + ] + + for idx, from_ in enumerate(strings): + # wide -> narrow: exceed maxchar limitation + for to in strings[:idx]: + self.assertRaises( + SystemError, + unicode_copycharacters, to, 0, from_, 0, 5 + ) + # same kind + for from_start in range(5): + self.assertEqual( + unicode_copycharacters(from_, 0, from_, from_start, 5), + (from_[from_start:from_start+5].ljust(5, '\0'), + 5-from_start) + ) + for to_start in range(5): + self.assertEqual( + unicode_copycharacters(from_, to_start, from_, to_start, 5), + (from_[to_start:to_start+5].rjust(5, '\0'), + 5-to_start) + ) + # narrow -> wide + # Tests omitted since this creates invalid strings. + + s = strings[0] + self.assertRaises(IndexError, unicode_copycharacters, s, 6, s, 0, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, -1, s, 0, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, 6, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, -1, 5) + self.assertRaises(SystemError, unicode_copycharacters, s, 1, s, 0, 5) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, s, 0, -1) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, b'', 0, 0) + @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). + Patch by Xiang Zhang. + - Issue #28376: The type of long range iterator is now registered as Iterator. Patch by Oren Milman. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1859,6 +1859,39 @@ } static PyObject * +unicode_copycharacters(PyObject *self, PyObject *args) +{ + PyObject *from, *to, *to_copy; + Py_ssize_t from_start, to_start, how_many, copied; + + if (!PyArg_ParseTuple(args, "UnOnn:unicode_copycharacters", &to, &to_start, + &from, &from_start, &how_many)) { + return NULL; + } + + if (PyUnicode_READY(to) < 0) { + return NULL; + } + + if (!(to_copy = PyUnicode_New(PyUnicode_GET_LENGTH(to), + PyUnicode_MAX_CHAR_VALUE(to)))) { + return NULL; + } + if (PyUnicode_Fill(to_copy, 0, PyUnicode_GET_LENGTH(to_copy), 0U) < 0) { + Py_DECREF(to_copy); + return NULL; + } + + if ((copied = PyUnicode_CopyCharacters(to_copy, to_start, from, + from_start, how_many)) < 0) { + Py_DECREF(to_copy); + return NULL; + } + + return Py_BuildValue("(Nn)", to_copy, copied); +} + +static PyObject * unicode_encodedecimal(PyObject *self, PyObject *args) { Py_UNICODE *unicode; @@ -4061,6 +4094,7 @@ {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, {"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS}, {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, + {"unicode_copycharacters", unicode_copycharacters, METH_VARARGS}, {"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS}, {"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS}, {"unicode_legacy_string", unicode_legacy_string, METH_VARARGS}, diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1549,15 +1549,19 @@ if (PyUnicode_READY(to) == -1) return -1; - if (from_start < 0) { + if ((size_t)from_start > (size_t)PyUnicode_GET_LENGTH(from)) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } - if (to_start < 0) { + if ((size_t)to_start > (size_t)PyUnicode_GET_LENGTH(to)) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } - how_many = Py_MIN(PyUnicode_GET_LENGTH(from), how_many); + if (how_many < 0) { + PyErr_SetString(PyExc_SystemError, "how_many cannot be negative"); + return -1; + } + how_many = Py_MIN(PyUnicode_GET_LENGTH(from)-from_start, how_many); if (to_start + how_many > PyUnicode_GET_LENGTH(to)) { PyErr_Format(PyExc_SystemError, "Cannot write %zi characters at %zi " -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 15:48:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 08 Oct 2016 19:48:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjYu?= Message-ID: <20161008194828.20829.26211.009345E2@psf.io> https://hg.python.org/cpython/rev/39511e854e6d changeset: 104396:39511e854e6d parent: 104393:947fa496ca6f parent: 104395:6803a6478056 user: Serhiy Storchaka date: Sat Oct 08 22:48:07 2016 +0300 summary: Merge from 3.6. files: Doc/c-api/unicode.rst | 9 +++- Lib/test/test_unicode.py | 45 ++++++++++++++++++++++++++- Misc/NEWS | 3 + Modules/_testcapimodule.c | 34 ++++++++++++++++++++ Objects/unicodeobject.c | 10 ++++- 5 files changed, 94 insertions(+), 7 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 @@ -572,13 +572,16 @@ .. versionadded:: 3.3 -.. c:function:: int PyUnicode_CopyCharacters(PyObject *to, Py_ssize_t to_start, \ - PyObject *from, Py_ssize_t from_start, Py_ssize_t how_many) +.. c:function:: Py_ssize_t PyUnicode_CopyCharacters(PyObject *to, \ + Py_ssize_t to_start, \ + PyObject *from, \ + Py_ssize_t from_start, \ + Py_ssize_t how_many) Copy characters from one Unicode object into another. This function performs character conversion when necessary and falls back to :c:func:`memcpy` if possible. Returns ``-1`` and sets an exception on error, otherwise returns - ``0``. + the number of copied characters. .. versionadded:: 3.3 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 @@ -4,7 +4,7 @@ (c) Copyright CNRI, All Rights Reserved. NO WARRANTY. -"""#" +""" import _string import codecs import itertools @@ -2735,6 +2735,49 @@ self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + # Test PyUnicode_CopyCharacters() + @support.cpython_only + def test_copycharacters(self): + from _testcapi import unicode_copycharacters + + strings = [ + 'abcde', '\xa1\xa2\xa3\xa4\xa5', + '\u4f60\u597d\u4e16\u754c\uff01', + '\U0001f600\U0001f601\U0001f602\U0001f603\U0001f604' + ] + + for idx, from_ in enumerate(strings): + # wide -> narrow: exceed maxchar limitation + for to in strings[:idx]: + self.assertRaises( + SystemError, + unicode_copycharacters, to, 0, from_, 0, 5 + ) + # same kind + for from_start in range(5): + self.assertEqual( + unicode_copycharacters(from_, 0, from_, from_start, 5), + (from_[from_start:from_start+5].ljust(5, '\0'), + 5-from_start) + ) + for to_start in range(5): + self.assertEqual( + unicode_copycharacters(from_, to_start, from_, to_start, 5), + (from_[to_start:to_start+5].rjust(5, '\0'), + 5-to_start) + ) + # narrow -> wide + # Tests omitted since this creates invalid strings. + + s = strings[0] + self.assertRaises(IndexError, unicode_copycharacters, s, 6, s, 0, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, -1, s, 0, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, 6, 5) + self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, -1, 5) + self.assertRaises(SystemError, unicode_copycharacters, s, 1, s, 0, 5) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, s, 0, -1) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, b'', 0, 0) + @support.cpython_only def test_encode_decimal(self): from _testcapi import unicode_encodedecimal diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). + Patch by Xiang Zhang. + - Issue #28376: The type of long range iterator is now registered as Iterator. Patch by Oren Milman. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1859,6 +1859,39 @@ } static PyObject * +unicode_copycharacters(PyObject *self, PyObject *args) +{ + PyObject *from, *to, *to_copy; + Py_ssize_t from_start, to_start, how_many, copied; + + if (!PyArg_ParseTuple(args, "UnOnn:unicode_copycharacters", &to, &to_start, + &from, &from_start, &how_many)) { + return NULL; + } + + if (PyUnicode_READY(to) < 0) { + return NULL; + } + + if (!(to_copy = PyUnicode_New(PyUnicode_GET_LENGTH(to), + PyUnicode_MAX_CHAR_VALUE(to)))) { + return NULL; + } + if (PyUnicode_Fill(to_copy, 0, PyUnicode_GET_LENGTH(to_copy), 0U) < 0) { + Py_DECREF(to_copy); + return NULL; + } + + if ((copied = PyUnicode_CopyCharacters(to_copy, to_start, from, + from_start, how_many)) < 0) { + Py_DECREF(to_copy); + return NULL; + } + + return Py_BuildValue("(Nn)", to_copy, copied); +} + +static PyObject * unicode_encodedecimal(PyObject *self, PyObject *args) { Py_UNICODE *unicode; @@ -4061,6 +4094,7 @@ {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, {"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS}, {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, + {"unicode_copycharacters", unicode_copycharacters, METH_VARARGS}, {"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS}, {"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS}, {"unicode_legacy_string", unicode_legacy_string, METH_VARARGS}, diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1549,15 +1549,19 @@ if (PyUnicode_READY(to) == -1) return -1; - if (from_start < 0) { + if ((size_t)from_start > (size_t)PyUnicode_GET_LENGTH(from)) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } - if (to_start < 0) { + if ((size_t)to_start > (size_t)PyUnicode_GET_LENGTH(to)) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } - how_many = Py_MIN(PyUnicode_GET_LENGTH(from), how_many); + if (how_many < 0) { + PyErr_SetString(PyExc_SystemError, "how_many cannot be negative"); + return -1; + } + how_many = Py_MIN(PyUnicode_GET_LENGTH(from)-from_start, how_many); if (to_start + how_many > PyUnicode_GET_LENGTH(to)) { PyErr_Format(PyExc_SystemError, "Cannot write %zi characters at %zi " -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:10:35 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:10:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328388=3A_update_typing_module_documentation=2E_?= =?utf-8?b?KG1lcmdlIDMuNi0+My43KQ==?= Message-ID: <20161009031035.1540.70686.39401637@psf.io> https://hg.python.org/cpython/rev/6cb9dfe4cbeb changeset: 104399:6cb9dfe4cbeb parent: 104396:39511e854e6d parent: 104398:589e11c3489e user: Guido van Rossum date: Sat Oct 08 20:10:27 2016 -0700 summary: Issue #28388: update typing module documentation. (merge 3.6->3.7) files: Doc/library/typing.rst | 249 ++++++++++++++-------------- 1 files changed, 126 insertions(+), 123 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -10,9 +10,9 @@ -------------- -This module supports type hints as specified by :pep:`484` and :pep:`526`. The most -fundamental support consists of the type :class:`Any`, :class:`Union`, -:class:`Tuple`, :class:`Callable`, :class:`TypeVar`, and +This module supports type hints as specified by :pep:`484` and :pep:`526`. +The most fundamental support consists of the type :data:`Any`, :data:`Union`, +:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and :class:`Generic`. For full specification please see :pep:`484`. For a simplified introduction to type hints see :pep:`483`. @@ -266,8 +266,8 @@ In this case ``MyDict`` has a single parameter, ``T``. -Subclassing a generic class without specifying type parameters assumes -:class:`Any` for each position. In the following example, ``MyIterable`` is +Using a generic class without specifying type parameters assumes +:data:`Any` for each position. In the following example, ``MyIterable`` is not generic but implicitly inherits from ``Iterable[Any]``:: from typing import Iterable @@ -277,18 +277,20 @@ The metaclass used by :class:`Generic` is a subclass of :class:`abc.ABCMeta`. A generic class can be an ABC by including abstract methods or properties, and generic classes can also have ABCs as base classes without a metaclass -conflict. Generic metaclasses are not supported. +conflict. Generic metaclasses are not supported. The outcome of parameterizing +generics is cached, and most types in the typing module are hashable and +comparable for equality. -The :class:`Any` type +The :data:`Any` type --------------------- -A special kind of type is :class:`Any`. A static type checker will treat -every type as being compatible with :class:`Any` and :class:`Any` as being +A special kind of type is :data:`Any`. A static type checker will treat +every type as being compatible with :data:`Any` and :data:`Any` as being compatible with every type. This means that it is possible to perform any operation or method call on a -value of type on :class:`Any` and assign it to any variable:: +value of type on :data:`Any` and assign it to any variable:: from typing import Any @@ -306,13 +308,13 @@ ... Notice that no typechecking is performed when assigning a value of type -:class:`Any` to a more precise type. For example, the static type checker did +:data:`Any` to a more precise type. For example, the static type checker did not report an error when assigning ``a`` to ``s`` even though ``s`` was declared to be of type :class:`str` and receives an :class:`int` value at runtime! Furthermore, all functions without a return type or parameter types will -implicitly default to using :class:`Any`:: +implicitly default to using :data:`Any`:: def legacy_parser(text): ... @@ -324,12 +326,12 @@ ... return data -This behavior allows :class:`Any` to be used as an *escape hatch* when you +This behavior allows :data:`Any` to be used as an *escape hatch* when you need to mix dynamically and statically typed code. -Contrast the behavior of :class:`Any` with the behavior of :class:`object`. -Similar to :class:`Any`, every type is a subtype of :class:`object`. However, -unlike :class:`Any`, the reverse is not true: :class:`object` is *not* a +Contrast the behavior of :data:`Any` with the behavior of :class:`object`. +Similar to :data:`Any`, every type is a subtype of :class:`object`. However, +unlike :data:`Any`, the reverse is not true: :class:`object` is *not* a subtype of every other type. That means when the type of a value is :class:`object`, a type checker will @@ -355,22 +357,13 @@ hash_b("foo") Use :class:`object` to indicate that a value could be any type in a typesafe -manner. Use :class:`Any` to indicate that a value is dynamically typed. +manner. Use :data:`Any` to indicate that a value is dynamically typed. Classes, functions, and decorators ---------------------------------- The module defines the following classes, functions and decorators: -.. class:: Any - - Special type indicating an unconstrained type. - - * Any object is an instance of :class:`Any`. - * Any class is a subclass of :class:`Any`. - * As a special case, :class:`Any` and :class:`object` are subclasses of - each other. - .. class:: TypeVar Type variable. @@ -409,79 +402,6 @@ for the type variable must be a subclass of the boundary type, see :pep:`484`. -.. class:: Union - - Union type; ``Union[X, Y]`` means either X or Y. - - To define a union, use e.g. ``Union[int, str]``. Details: - - * The arguments must be types and there must be at least one. - - * Unions of unions are flattened, e.g.:: - - Union[Union[int, str], float] == Union[int, str, float] - - * Unions of a single argument vanish, e.g.:: - - Union[int] == int # The constructor actually returns int - - * Redundant arguments are skipped, e.g.:: - - Union[int, str, int] == Union[int, str] - - * When comparing unions, the argument order is ignored, e.g.:: - - Union[int, str] == Union[str, int] - - * If :class:`Any` is present it is the sole survivor, e.g.:: - - Union[int, Any] == Any - - * You cannot subclass or instantiate a union. - - * You cannot write ``Union[X][Y]``. - - * You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``. - -.. class:: Optional - - Optional type. - - ``Optional[X]`` is equivalent to ``Union[X, None]``. - - Note that this is not the same concept as an optional argument, - which is one that has a default. An optional argument with a - default needn't use the ``Optional`` qualifier on its type - annotation (although it is inferred if the default is ``None``). - A mandatory argument may still have an ``Optional`` type if an - explicit value of ``None`` is allowed. - -.. class:: Tuple - - Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items - with the first item of type X and the second of type Y. - - Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding - to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, - use literal ellipsis, e.g. ``Tuple[int, ...]``. - -.. class:: Callable - - Callable type; ``Callable[[int], str]`` is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - ``Callable[..., ReturnType]`` could be used to type hint a callable - taking any number of arguments and returning ``ReturnType``. - A plain :class:`Callable` is equivalent to ``Callable[..., Any]``. - .. class:: Generic Abstract base class for generic types. @@ -506,7 +426,7 @@ except KeyError: return default -.. class:: Type +.. class:: Type(Generic[CT_co]) A variable annotated with ``C`` may accept a value of type ``C``. In contrast, a variable annotated with ``Type[C]`` may accept values that are @@ -538,7 +458,7 @@ :pep:`484`. The only legal parameters for :class:`Type` are classes, unions of classes, and - :class:`Any`. For example:: + :data:`Any`. For example:: def new_non_team_user(user_class: Type[Union[BaseUser, ProUser]]): ... @@ -725,21 +645,6 @@ yield start start += 1 -.. class:: AnyStr - - ``AnyStr`` is a type variable defined as - ``AnyStr = TypeVar('AnyStr', str, bytes)``. - - It is meant to be used for functions that may accept any kind of string - without allowing different kinds of strings to mix. For example:: - - def concat(a: AnyStr, b: AnyStr) -> AnyStr: - return a + b - - concat(u"foo", u"bar") # Ok, output has type 'unicode' - concat(b"foo", b"bar") # Ok, output has type 'bytes' - concat(u"foo", b"bar") # Error, cannot mix unicode and bytes - .. class:: Text ``Text`` is an alias for ``str``. It is provided to supply a forward @@ -860,6 +765,89 @@ This wraps the decorator with something that wraps the decorated function in :func:`no_type_check`. +.. data:: Any + + Special type indicating an unconstrained type. + + * Every type is compatible with :data:`Any`. + * :data:`Any` is compatible with every type. + +.. data:: Union + + Union type; ``Union[X, Y]`` means either X or Y. + + To define a union, use e.g. ``Union[int, str]``. Details: + + * The arguments must be types and there must be at least one. + + * Unions of unions are flattened, e.g.:: + + Union[Union[int, str], float] == Union[int, str, float] + + * Unions of a single argument vanish, e.g.:: + + Union[int] == int # The constructor actually returns int + + * Redundant arguments are skipped, e.g.:: + + Union[int, str, int] == Union[int, str] + + * When comparing unions, the argument order is ignored, e.g.:: + + Union[int, str] == Union[str, int] + + * When a class and its subclass are present, the former is skipped, e.g.:: + + Union[int, object] == object + + * You cannot subclass or instantiate a union. + + * You cannot write ``Union[X][Y]``. + + * You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``. + +.. data:: Optional + + Optional type. + + ``Optional[X]`` is equivalent to ``Union[X, None]``. + + Note that this is not the same concept as an optional argument, + which is one that has a default. An optional argument with a + default needn't use the ``Optional`` qualifier on its type + annotation (although it is inferred if the default is ``None``). + A mandatory argument may still have an ``Optional`` type if an + explicit value of ``None`` is allowed. + +.. data:: Tuple + + Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items + with the first item of type X and the second of type Y. + + Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding + to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple + of an int, a float and a string. + + To specify a variable-length tuple of homogeneous type, + use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain :data:`Tuple` + is equivalent to ``Tuple[Any, ...]``, and in turn to :data:`tuple`. + +.. data:: Callable + + Callable type; ``Callable[[int], str]`` is a function of (int) -> str. + + The subscription syntax must always be used with exactly two + values: the argument list and the return type. The argument list + must be a list of types; the return type must be a single type. + + There is no syntax to indicate optional or keyword arguments; + such function types are rarely used as callback types. + ``Callable[..., ReturnType]`` (literal ellipsis) can be used to + type hint a callable taking any number of arguments and returning + ``ReturnType``. A plain :data:`Callable` is equivalent to + ``Callable[..., Any]``, and in turn to + :class:`collections.abc.Callable`. + .. data:: ClassVar Special type construct to mark class variables. @@ -872,19 +860,34 @@ stats: ClassVar[Dict[str, int]] = {} # class variable damage: int = 10 # instance variable - ClassVar accepts only types and cannot be further subscribed. + :data:`ClassVar` accepts only types and cannot be further subscribed. - ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). Note that ClassVar - does not change Python runtime behavior, it can be used by - 3rd party type checkers, so that the following code will - flagged as an error by those:: + :data:`ClassVar` is not a class itself, and should not + be used with :func:`isinstance` or :func:`issubclass`. + Note that :data:`ClassVar` does not change Python runtime behavior; + it can be used by 3rd party type checkers, so that the following + code might flagged as an error by those:: enterprise_d = Starship(3000) enterprise_d.stats = {} # Error, setting class variable on instance Starship.stats = {} # This is OK - .. versionadded:: 3.6 + .. versionadded:: 3.5.3 + +.. data:: AnyStr + + ``AnyStr`` is a type variable defined as + ``AnyStr = TypeVar('AnyStr', str, bytes)``. + + It is meant to be used for functions that may accept any kind of string + without allowing different kinds of strings to mix. For example:: + + def concat(a: AnyStr, b: AnyStr) -> AnyStr: + return a + b + + concat(u"foo", u"bar") # Ok, output has type 'unicode' + concat(b"foo", b"bar") # Ok, output has type 'bytes' + concat(u"foo", b"bar") # Error, cannot mix unicode and bytes .. data:: TYPE_CHECKING -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:10:35 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:10:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328388=3A_update_typing_module_documentation=2E_=28mer?= =?utf-8?b?Z2UgMy41LT4zLjYp?= Message-ID: <20161009031035.82281.18386.F2B0FA40@psf.io> https://hg.python.org/cpython/rev/589e11c3489e changeset: 104398:589e11c3489e branch: 3.6 parent: 104395:6803a6478056 parent: 104397:9953efbb4974 user: Guido van Rossum date: Sat Oct 08 20:09:56 2016 -0700 summary: Issue #28388: update typing module documentation. (merge 3.5->3.6) files: Doc/library/typing.rst | 249 ++++++++++++++-------------- 1 files changed, 126 insertions(+), 123 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -10,9 +10,9 @@ -------------- -This module supports type hints as specified by :pep:`484` and :pep:`526`. The most -fundamental support consists of the type :class:`Any`, :class:`Union`, -:class:`Tuple`, :class:`Callable`, :class:`TypeVar`, and +This module supports type hints as specified by :pep:`484` and :pep:`526`. +The most fundamental support consists of the type :data:`Any`, :data:`Union`, +:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and :class:`Generic`. For full specification please see :pep:`484`. For a simplified introduction to type hints see :pep:`483`. @@ -266,8 +266,8 @@ In this case ``MyDict`` has a single parameter, ``T``. -Subclassing a generic class without specifying type parameters assumes -:class:`Any` for each position. In the following example, ``MyIterable`` is +Using a generic class without specifying type parameters assumes +:data:`Any` for each position. In the following example, ``MyIterable`` is not generic but implicitly inherits from ``Iterable[Any]``:: from typing import Iterable @@ -277,18 +277,20 @@ The metaclass used by :class:`Generic` is a subclass of :class:`abc.ABCMeta`. A generic class can be an ABC by including abstract methods or properties, and generic classes can also have ABCs as base classes without a metaclass -conflict. Generic metaclasses are not supported. +conflict. Generic metaclasses are not supported. The outcome of parameterizing +generics is cached, and most types in the typing module are hashable and +comparable for equality. -The :class:`Any` type +The :data:`Any` type --------------------- -A special kind of type is :class:`Any`. A static type checker will treat -every type as being compatible with :class:`Any` and :class:`Any` as being +A special kind of type is :data:`Any`. A static type checker will treat +every type as being compatible with :data:`Any` and :data:`Any` as being compatible with every type. This means that it is possible to perform any operation or method call on a -value of type on :class:`Any` and assign it to any variable:: +value of type on :data:`Any` and assign it to any variable:: from typing import Any @@ -306,13 +308,13 @@ ... Notice that no typechecking is performed when assigning a value of type -:class:`Any` to a more precise type. For example, the static type checker did +:data:`Any` to a more precise type. For example, the static type checker did not report an error when assigning ``a`` to ``s`` even though ``s`` was declared to be of type :class:`str` and receives an :class:`int` value at runtime! Furthermore, all functions without a return type or parameter types will -implicitly default to using :class:`Any`:: +implicitly default to using :data:`Any`:: def legacy_parser(text): ... @@ -324,12 +326,12 @@ ... return data -This behavior allows :class:`Any` to be used as an *escape hatch* when you +This behavior allows :data:`Any` to be used as an *escape hatch* when you need to mix dynamically and statically typed code. -Contrast the behavior of :class:`Any` with the behavior of :class:`object`. -Similar to :class:`Any`, every type is a subtype of :class:`object`. However, -unlike :class:`Any`, the reverse is not true: :class:`object` is *not* a +Contrast the behavior of :data:`Any` with the behavior of :class:`object`. +Similar to :data:`Any`, every type is a subtype of :class:`object`. However, +unlike :data:`Any`, the reverse is not true: :class:`object` is *not* a subtype of every other type. That means when the type of a value is :class:`object`, a type checker will @@ -355,22 +357,13 @@ hash_b("foo") Use :class:`object` to indicate that a value could be any type in a typesafe -manner. Use :class:`Any` to indicate that a value is dynamically typed. +manner. Use :data:`Any` to indicate that a value is dynamically typed. Classes, functions, and decorators ---------------------------------- The module defines the following classes, functions and decorators: -.. class:: Any - - Special type indicating an unconstrained type. - - * Any object is an instance of :class:`Any`. - * Any class is a subclass of :class:`Any`. - * As a special case, :class:`Any` and :class:`object` are subclasses of - each other. - .. class:: TypeVar Type variable. @@ -409,79 +402,6 @@ for the type variable must be a subclass of the boundary type, see :pep:`484`. -.. class:: Union - - Union type; ``Union[X, Y]`` means either X or Y. - - To define a union, use e.g. ``Union[int, str]``. Details: - - * The arguments must be types and there must be at least one. - - * Unions of unions are flattened, e.g.:: - - Union[Union[int, str], float] == Union[int, str, float] - - * Unions of a single argument vanish, e.g.:: - - Union[int] == int # The constructor actually returns int - - * Redundant arguments are skipped, e.g.:: - - Union[int, str, int] == Union[int, str] - - * When comparing unions, the argument order is ignored, e.g.:: - - Union[int, str] == Union[str, int] - - * If :class:`Any` is present it is the sole survivor, e.g.:: - - Union[int, Any] == Any - - * You cannot subclass or instantiate a union. - - * You cannot write ``Union[X][Y]``. - - * You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``. - -.. class:: Optional - - Optional type. - - ``Optional[X]`` is equivalent to ``Union[X, None]``. - - Note that this is not the same concept as an optional argument, - which is one that has a default. An optional argument with a - default needn't use the ``Optional`` qualifier on its type - annotation (although it is inferred if the default is ``None``). - A mandatory argument may still have an ``Optional`` type if an - explicit value of ``None`` is allowed. - -.. class:: Tuple - - Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items - with the first item of type X and the second of type Y. - - Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding - to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, - use literal ellipsis, e.g. ``Tuple[int, ...]``. - -.. class:: Callable - - Callable type; ``Callable[[int], str]`` is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - ``Callable[..., ReturnType]`` could be used to type hint a callable - taking any number of arguments and returning ``ReturnType``. - A plain :class:`Callable` is equivalent to ``Callable[..., Any]``. - .. class:: Generic Abstract base class for generic types. @@ -506,7 +426,7 @@ except KeyError: return default -.. class:: Type +.. class:: Type(Generic[CT_co]) A variable annotated with ``C`` may accept a value of type ``C``. In contrast, a variable annotated with ``Type[C]`` may accept values that are @@ -538,7 +458,7 @@ :pep:`484`. The only legal parameters for :class:`Type` are classes, unions of classes, and - :class:`Any`. For example:: + :data:`Any`. For example:: def new_non_team_user(user_class: Type[Union[BaseUser, ProUser]]): ... @@ -725,21 +645,6 @@ yield start start += 1 -.. class:: AnyStr - - ``AnyStr`` is a type variable defined as - ``AnyStr = TypeVar('AnyStr', str, bytes)``. - - It is meant to be used for functions that may accept any kind of string - without allowing different kinds of strings to mix. For example:: - - def concat(a: AnyStr, b: AnyStr) -> AnyStr: - return a + b - - concat(u"foo", u"bar") # Ok, output has type 'unicode' - concat(b"foo", b"bar") # Ok, output has type 'bytes' - concat(u"foo", b"bar") # Error, cannot mix unicode and bytes - .. class:: Text ``Text`` is an alias for ``str``. It is provided to supply a forward @@ -860,6 +765,89 @@ This wraps the decorator with something that wraps the decorated function in :func:`no_type_check`. +.. data:: Any + + Special type indicating an unconstrained type. + + * Every type is compatible with :data:`Any`. + * :data:`Any` is compatible with every type. + +.. data:: Union + + Union type; ``Union[X, Y]`` means either X or Y. + + To define a union, use e.g. ``Union[int, str]``. Details: + + * The arguments must be types and there must be at least one. + + * Unions of unions are flattened, e.g.:: + + Union[Union[int, str], float] == Union[int, str, float] + + * Unions of a single argument vanish, e.g.:: + + Union[int] == int # The constructor actually returns int + + * Redundant arguments are skipped, e.g.:: + + Union[int, str, int] == Union[int, str] + + * When comparing unions, the argument order is ignored, e.g.:: + + Union[int, str] == Union[str, int] + + * When a class and its subclass are present, the former is skipped, e.g.:: + + Union[int, object] == object + + * You cannot subclass or instantiate a union. + + * You cannot write ``Union[X][Y]``. + + * You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``. + +.. data:: Optional + + Optional type. + + ``Optional[X]`` is equivalent to ``Union[X, None]``. + + Note that this is not the same concept as an optional argument, + which is one that has a default. An optional argument with a + default needn't use the ``Optional`` qualifier on its type + annotation (although it is inferred if the default is ``None``). + A mandatory argument may still have an ``Optional`` type if an + explicit value of ``None`` is allowed. + +.. data:: Tuple + + Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items + with the first item of type X and the second of type Y. + + Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding + to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple + of an int, a float and a string. + + To specify a variable-length tuple of homogeneous type, + use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain :data:`Tuple` + is equivalent to ``Tuple[Any, ...]``, and in turn to :data:`tuple`. + +.. data:: Callable + + Callable type; ``Callable[[int], str]`` is a function of (int) -> str. + + The subscription syntax must always be used with exactly two + values: the argument list and the return type. The argument list + must be a list of types; the return type must be a single type. + + There is no syntax to indicate optional or keyword arguments; + such function types are rarely used as callback types. + ``Callable[..., ReturnType]`` (literal ellipsis) can be used to + type hint a callable taking any number of arguments and returning + ``ReturnType``. A plain :data:`Callable` is equivalent to + ``Callable[..., Any]``, and in turn to + :class:`collections.abc.Callable`. + .. data:: ClassVar Special type construct to mark class variables. @@ -872,19 +860,34 @@ stats: ClassVar[Dict[str, int]] = {} # class variable damage: int = 10 # instance variable - ClassVar accepts only types and cannot be further subscribed. + :data:`ClassVar` accepts only types and cannot be further subscribed. - ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). Note that ClassVar - does not change Python runtime behavior, it can be used by - 3rd party type checkers, so that the following code will - flagged as an error by those:: + :data:`ClassVar` is not a class itself, and should not + be used with :func:`isinstance` or :func:`issubclass`. + Note that :data:`ClassVar` does not change Python runtime behavior; + it can be used by 3rd party type checkers, so that the following + code might flagged as an error by those:: enterprise_d = Starship(3000) enterprise_d.stats = {} # Error, setting class variable on instance Starship.stats = {} # This is OK - .. versionadded:: 3.6 + .. versionadded:: 3.5.3 + +.. data:: AnyStr + + ``AnyStr`` is a type variable defined as + ``AnyStr = TypeVar('AnyStr', str, bytes)``. + + It is meant to be used for functions that may accept any kind of string + without allowing different kinds of strings to mix. For example:: + + def concat(a: AnyStr, b: AnyStr) -> AnyStr: + return a + b + + concat(u"foo", u"bar") # Ok, output has type 'unicode' + concat(b"foo", b"bar") # Ok, output has type 'bytes' + concat(u"foo", b"bar") # Error, cannot mix unicode and bytes .. data:: TYPE_CHECKING -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:10:35 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:10:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzg4?= =?utf-8?q?=3A_update_typing_module_documentation=2E?= Message-ID: <20161009031035.1375.22636.A9C3F1E5@psf.io> https://hg.python.org/cpython/rev/9953efbb4974 changeset: 104397:9953efbb4974 branch: 3.5 parent: 104394:13addd71b751 user: Guido van Rossum date: Sat Oct 08 20:06:56 2016 -0700 summary: Issue #28388: update typing module documentation. files: Doc/library/typing.rst | 247 ++++++++++++++-------------- 1 files changed, 125 insertions(+), 122 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -11,8 +11,8 @@ -------------- This module supports type hints as specified by :pep:`484`. The most -fundamental support consists of the type :class:`Any`, :class:`Union`, -:class:`Tuple`, :class:`Callable`, :class:`TypeVar`, and +fundamental support consists of the type :data:`Any`, :data:`Union`, +:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and :class:`Generic`. For full specification please see :pep:`484`. For a simplified introduction to type hints see :pep:`483`. @@ -266,8 +266,8 @@ In this case ``MyDict`` has a single parameter, ``T``. -Subclassing a generic class without specifying type parameters assumes -:class:`Any` for each position. In the following example, ``MyIterable`` is +Using a generic class without specifying type parameters assumes +:data:`Any` for each position. In the following example, ``MyIterable`` is not generic but implicitly inherits from ``Iterable[Any]``:: from typing import Iterable @@ -277,18 +277,20 @@ The metaclass used by :class:`Generic` is a subclass of :class:`abc.ABCMeta`. A generic class can be an ABC by including abstract methods or properties, and generic classes can also have ABCs as base classes without a metaclass -conflict. Generic metaclasses are not supported. +conflict. Generic metaclasses are not supported. The outcome of parameterizing +generics is cached, and most types in the typing module are hashable and +comparable for equality. -The :class:`Any` type +The :data:`Any` type --------------------- -A special kind of type is :class:`Any`. A static type checker will treat -every type as being compatible with :class:`Any` and :class:`Any` as being +A special kind of type is :data:`Any`. A static type checker will treat +every type as being compatible with :data:`Any` and :data:`Any` as being compatible with every type. This means that it is possible to perform any operation or method call on a -value of type on :class:`Any` and assign it to any variable:: +value of type on :data:`Any` and assign it to any variable:: from typing import Any @@ -306,13 +308,13 @@ ... Notice that no typechecking is performed when assigning a value of type -:class:`Any` to a more precise type. For example, the static type checker did +:data:`Any` to a more precise type. For example, the static type checker did not report an error when assigning ``a`` to ``s`` even though ``s`` was declared to be of type :class:`str` and receives an :class:`int` value at runtime! Furthermore, all functions without a return type or parameter types will -implicitly default to using :class:`Any`:: +implicitly default to using :data:`Any`:: def legacy_parser(text): ... @@ -324,12 +326,12 @@ ... return data -This behavior allows :class:`Any` to be used as an *escape hatch* when you +This behavior allows :data:`Any` to be used as an *escape hatch* when you need to mix dynamically and statically typed code. -Contrast the behavior of :class:`Any` with the behavior of :class:`object`. -Similar to :class:`Any`, every type is a subtype of :class:`object`. However, -unlike :class:`Any`, the reverse is not true: :class:`object` is *not* a +Contrast the behavior of :data:`Any` with the behavior of :class:`object`. +Similar to :data:`Any`, every type is a subtype of :class:`object`. However, +unlike :data:`Any`, the reverse is not true: :class:`object` is *not* a subtype of every other type. That means when the type of a value is :class:`object`, a type checker will @@ -355,22 +357,13 @@ hash_b("foo") Use :class:`object` to indicate that a value could be any type in a typesafe -manner. Use :class:`Any` to indicate that a value is dynamically typed. +manner. Use :data:`Any` to indicate that a value is dynamically typed. Classes, functions, and decorators ---------------------------------- The module defines the following classes, functions and decorators: -.. class:: Any - - Special type indicating an unconstrained type. - - * Any object is an instance of :class:`Any`. - * Any class is a subclass of :class:`Any`. - * As a special case, :class:`Any` and :class:`object` are subclasses of - each other. - .. class:: TypeVar Type variable. @@ -409,79 +402,6 @@ for the type variable must be a subclass of the boundary type, see :pep:`484`. -.. class:: Union - - Union type; ``Union[X, Y]`` means either X or Y. - - To define a union, use e.g. ``Union[int, str]``. Details: - - * The arguments must be types and there must be at least one. - - * Unions of unions are flattened, e.g.:: - - Union[Union[int, str], float] == Union[int, str, float] - - * Unions of a single argument vanish, e.g.:: - - Union[int] == int # The constructor actually returns int - - * Redundant arguments are skipped, e.g.:: - - Union[int, str, int] == Union[int, str] - - * When comparing unions, the argument order is ignored, e.g.:: - - Union[int, str] == Union[str, int] - - * If :class:`Any` is present it is the sole survivor, e.g.:: - - Union[int, Any] == Any - - * You cannot subclass or instantiate a union. - - * You cannot write ``Union[X][Y]``. - - * You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``. - -.. class:: Optional - - Optional type. - - ``Optional[X]`` is equivalent to ``Union[X, None]``. - - Note that this is not the same concept as an optional argument, - which is one that has a default. An optional argument with a - default needn't use the ``Optional`` qualifier on its type - annotation (although it is inferred if the default is ``None``). - A mandatory argument may still have an ``Optional`` type if an - explicit value of ``None`` is allowed. - -.. class:: Tuple - - Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items - with the first item of type X and the second of type Y. - - Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding - to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, - use literal ellipsis, e.g. ``Tuple[int, ...]``. - -.. class:: Callable - - Callable type; ``Callable[[int], str]`` is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - ``Callable[..., ReturnType]`` could be used to type hint a callable - taking any number of arguments and returning ``ReturnType``. - A plain :class:`Callable` is equivalent to ``Callable[..., Any]``. - .. class:: Generic Abstract base class for generic types. @@ -506,7 +426,7 @@ except KeyError: return default -.. class:: Type +.. class:: Type(Generic[CT_co]) A variable annotated with ``C`` may accept a value of type ``C``. In contrast, a variable annotated with ``Type[C]`` may accept values that are @@ -538,7 +458,7 @@ :pep:`484`. The only legal parameters for :class:`Type` are classes, unions of classes, and - :class:`Any`. For example:: + :data:`Any`. For example:: def new_non_team_user(user_class: Type[Union[BaseUser, ProUser]]): ... @@ -713,21 +633,6 @@ yield start start += 1 -.. class:: AnyStr - - ``AnyStr`` is a type variable defined as - ``AnyStr = TypeVar('AnyStr', str, bytes)``. - - It is meant to be used for functions that may accept any kind of string - without allowing different kinds of strings to mix. For example:: - - def concat(a: AnyStr, b: AnyStr) -> AnyStr: - return a + b - - concat(u"foo", u"bar") # Ok, output has type 'unicode' - concat(b"foo", b"bar") # Ok, output has type 'bytes' - concat(u"foo", b"bar") # Error, cannot mix unicode and bytes - .. class:: Text ``Text`` is an alias for ``str``. It is provided to supply a forward @@ -848,6 +753,89 @@ This wraps the decorator with something that wraps the decorated function in :func:`no_type_check`. +.. data:: Any + + Special type indicating an unconstrained type. + + * Every type is compatible with :data:`Any`. + * :data:`Any` is compatible with every type. + +.. data:: Union + + Union type; ``Union[X, Y]`` means either X or Y. + + To define a union, use e.g. ``Union[int, str]``. Details: + + * The arguments must be types and there must be at least one. + + * Unions of unions are flattened, e.g.:: + + Union[Union[int, str], float] == Union[int, str, float] + + * Unions of a single argument vanish, e.g.:: + + Union[int] == int # The constructor actually returns int + + * Redundant arguments are skipped, e.g.:: + + Union[int, str, int] == Union[int, str] + + * When comparing unions, the argument order is ignored, e.g.:: + + Union[int, str] == Union[str, int] + + * When a class and its subclass are present, the former is skipped, e.g.:: + + Union[int, object] == object + + * You cannot subclass or instantiate a union. + + * You cannot write ``Union[X][Y]``. + + * You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``. + +.. data:: Optional + + Optional type. + + ``Optional[X]`` is equivalent to ``Union[X, None]``. + + Note that this is not the same concept as an optional argument, + which is one that has a default. An optional argument with a + default needn't use the ``Optional`` qualifier on its type + annotation (although it is inferred if the default is ``None``). + A mandatory argument may still have an ``Optional`` type if an + explicit value of ``None`` is allowed. + +.. data:: Tuple + + Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items + with the first item of type X and the second of type Y. + + Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding + to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple + of an int, a float and a string. + + To specify a variable-length tuple of homogeneous type, + use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain :data:`Tuple` + is equivalent to ``Tuple[Any, ...]``, and in turn to :data:`tuple`. + +.. data:: Callable + + Callable type; ``Callable[[int], str]`` is a function of (int) -> str. + + The subscription syntax must always be used with exactly two + values: the argument list and the return type. The argument list + must be a list of types; the return type must be a single type. + + There is no syntax to indicate optional or keyword arguments; + such function types are rarely used as callback types. + ``Callable[..., ReturnType]`` (literal ellipsis) can be used to + type hint a callable taking any number of arguments and returning + ``ReturnType``. A plain :data:`Callable` is equivalent to + ``Callable[..., Any]``, and in turn to + :class:`collections.abc.Callable`. + .. data:: ClassVar Special type construct to mark class variables. @@ -860,19 +848,34 @@ stats: ClassVar[Dict[str, int]] = {} # class variable damage: int = 10 # instance variable - ClassVar accepts only types and cannot be further subscribed. + :data:`ClassVar` accepts only types and cannot be further subscribed. - ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). Note that ClassVar - does not change Python runtime behavior, it can be used by - 3rd party type checkers, so that the following code will - flagged as an error by those:: + :data:`ClassVar` is not a class itself, and should not + be used with :func:`isinstance` or :func:`issubclass`. + Note that :data:`ClassVar` does not change Python runtime behavior; + it can be used by 3rd party type checkers, so that the following + code might flagged as an error by those:: enterprise_d = Starship(3000) enterprise_d.stats = {} # Error, setting class variable on instance Starship.stats = {} # This is OK - .. versionadded:: 3.6 + .. versionadded:: 3.5.3 + +.. data:: AnyStr + + ``AnyStr`` is a type variable defined as + ``AnyStr = TypeVar('AnyStr', str, bytes)``. + + It is meant to be used for functions that may accept any kind of string + without allowing different kinds of strings to mix. For example:: + + def concat(a: AnyStr, b: AnyStr) -> AnyStr: + return a + b + + concat(u"foo", u"bar") # Ok, output has type 'unicode' + concat(b"foo", b"bar") # Ok, output has type 'bytes' + concat(u"foo", b"bar") # Error, cannot mix unicode and bytes .. data:: TYPE_CHECKING -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:14:10 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:14:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Adjust_ClassVa?= =?utf-8?q?r_example_to_use_pre-PEP-526_syntax=2E_=28Issue_=2328388=29?= Message-ID: <20161009031410.17589.53025.54A51A77@psf.io> https://hg.python.org/cpython/rev/d7f2b0332343 changeset: 104400:d7f2b0332343 branch: 3.5 parent: 104397:9953efbb4974 user: Guido van Rossum date: Sat Oct 08 20:12:54 2016 -0700 summary: Adjust ClassVar example to use pre-PEP-526 syntax. (Issue #28388) files: Doc/library/typing.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -845,8 +845,8 @@ and should not be set on instances of that class. Usage:: class Starship: - stats: ClassVar[Dict[str, int]] = {} # class variable - damage: int = 10 # instance variable + stats = {} # type: ClassVar[Dict[str, int]] # class variable + damage = 10 # type: int # instance variable :data:`ClassVar` accepts only types and cannot be further subscribed. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:14:11 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:14:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_null_merge?= Message-ID: <20161009031410.15398.25581.4AEBF2F0@psf.io> https://hg.python.org/cpython/rev/e5f5eae344d4 changeset: 104402:e5f5eae344d4 parent: 104399:6cb9dfe4cbeb parent: 104401:be76b638c8aa user: Guido van Rossum date: Sat Oct 08 20:14:04 2016 -0700 summary: null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:14:11 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:14:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_null_merge?= Message-ID: <20161009031410.79613.32324.50DB9C27@psf.io> https://hg.python.org/cpython/rev/be76b638c8aa changeset: 104401:be76b638c8aa branch: 3.6 parent: 104398:589e11c3489e parent: 104400:d7f2b0332343 user: Guido van Rossum date: Sat Oct 08 20:13:45 2016 -0700 summary: null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:28:37 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:28:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Merge_further_?= =?utf-8?q?typing=2Epy_changes_from_upstream=2E?= Message-ID: <20161009032837.85581.51598.97D30DE2@psf.io> https://hg.python.org/cpython/rev/7871ec789a27 changeset: 104403:7871ec789a27 branch: 3.5 parent: 104400:d7f2b0332343 user: Guido van Rossum date: Sat Oct 08 20:27:22 2016 -0700 summary: Merge further typing.py changes from upstream. files: Lib/test/test_typing.py | 79 +++++++++++++++++++++++++++++ Lib/typing.py | 5 +- 2 files changed, 83 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -20,6 +20,7 @@ from typing import NamedTuple from typing import IO, TextIO, BinaryIO from typing import Pattern, Match +import abc import typing try: import collections.abc as collections_abc @@ -1385,6 +1386,8 @@ return 0 self.assertEqual(len(MMC()), 0) + assert callable(MMC.update) + self.assertIsInstance(MMC(), typing.Mapping) class MMB(typing.MutableMapping[KT, VT]): def __getitem__(self, k): @@ -1409,6 +1412,82 @@ self.assertIsSubclass(MMB, typing.Mapping) self.assertIsSubclass(MMC, typing.Mapping) + self.assertIsInstance(MMB[KT, VT](), typing.Mapping) + self.assertIsInstance(MMB[KT, VT](), collections.Mapping) + + self.assertIsSubclass(MMA, collections.Mapping) + self.assertIsSubclass(MMB, collections.Mapping) + self.assertIsSubclass(MMC, collections.Mapping) + + self.assertIsSubclass(MMB[str, str], typing.Mapping) + self.assertIsSubclass(MMC, MMA) + + class I(typing.Iterable): ... + self.assertNotIsSubclass(list, I) + + class G(typing.Generator[int, int, int]): ... + def g(): yield 0 + self.assertIsSubclass(G, typing.Generator) + self.assertIsSubclass(G, typing.Iterable) + if hasattr(collections, 'Generator'): + self.assertIsSubclass(G, collections.Generator) + self.assertIsSubclass(G, collections.Iterable) + self.assertNotIsSubclass(type(g), G) + + def test_subclassing_subclasshook(self): + + class Base(typing.Iterable): + @classmethod + def __subclasshook__(cls, other): + if other.__name__ == 'Foo': + return True + else: + return False + + class C(Base): ... + class Foo: ... + class Bar: ... + self.assertIsSubclass(Foo, Base) + self.assertIsSubclass(Foo, C) + self.assertNotIsSubclass(Bar, C) + + def test_subclassing_register(self): + + class A(typing.Container): ... + class B(A): ... + + class C: ... + A.register(C) + self.assertIsSubclass(C, A) + self.assertNotIsSubclass(C, B) + + class D: ... + B.register(D) + self.assertIsSubclass(D, A) + self.assertIsSubclass(D, B) + + class M(): ... + collections.MutableMapping.register(M) + self.assertIsSubclass(M, typing.Mapping) + + def test_collections_as_base(self): + + class M(collections.Mapping): ... + self.assertIsSubclass(M, typing.Mapping) + self.assertIsSubclass(M, typing.Iterable) + + class S(collections.MutableSequence): ... + self.assertIsSubclass(S, typing.MutableSequence) + self.assertIsSubclass(S, typing.Iterable) + + class I(collections.Iterable): ... + self.assertIsSubclass(I, typing.Iterable) + + class A(collections.Mapping, metaclass=abc.ABCMeta): ... + class B: ... + A.register(B) + self.assertIsSubclass(B, typing.Mapping) + class OtherABCTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -993,7 +993,10 @@ # This allows unparameterized generic collections to be used # with issubclass() and isinstance() in the same way as their # collections.abc counterparts (e.g., isinstance([], Iterable)). - self.__subclasshook__ = _make_subclasshook(self) + if ('__subclasshook__' not in namespace and extra # allow overriding + or hasattr(self.__subclasshook__, '__name__') and + self.__subclasshook__.__name__ == '__extrahook__'): + self.__subclasshook__ = _make_subclasshook(self) if isinstance(extra, abc.ABCMeta): self._abc_registry = extra._abc_registry return self -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:28:38 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:28:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_further_typing=2Epy_changes_from_upstream=2E_=28merge_3?= =?utf-8?b?LjUtPjMuNik=?= Message-ID: <20161009032838.94922.76662.48E4DC77@psf.io> https://hg.python.org/cpython/rev/5fd1db0266d4 changeset: 104404:5fd1db0266d4 branch: 3.6 parent: 104401:be76b638c8aa parent: 104403:7871ec789a27 user: Guido van Rossum date: Sat Oct 08 20:27:55 2016 -0700 summary: Merge further typing.py changes from upstream. (merge 3.5->3.6) files: Lib/test/test_typing.py | 79 +++++++++++++++++++++++++++++ Lib/typing.py | 5 +- 2 files changed, 83 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -20,6 +20,7 @@ from typing import NamedTuple from typing import IO, TextIO, BinaryIO from typing import Pattern, Match +import abc import typing try: import collections.abc as collections_abc @@ -1385,6 +1386,8 @@ return 0 self.assertEqual(len(MMC()), 0) + assert callable(MMC.update) + self.assertIsInstance(MMC(), typing.Mapping) class MMB(typing.MutableMapping[KT, VT]): def __getitem__(self, k): @@ -1409,6 +1412,82 @@ self.assertIsSubclass(MMB, typing.Mapping) self.assertIsSubclass(MMC, typing.Mapping) + self.assertIsInstance(MMB[KT, VT](), typing.Mapping) + self.assertIsInstance(MMB[KT, VT](), collections.Mapping) + + self.assertIsSubclass(MMA, collections.Mapping) + self.assertIsSubclass(MMB, collections.Mapping) + self.assertIsSubclass(MMC, collections.Mapping) + + self.assertIsSubclass(MMB[str, str], typing.Mapping) + self.assertIsSubclass(MMC, MMA) + + class I(typing.Iterable): ... + self.assertNotIsSubclass(list, I) + + class G(typing.Generator[int, int, int]): ... + def g(): yield 0 + self.assertIsSubclass(G, typing.Generator) + self.assertIsSubclass(G, typing.Iterable) + if hasattr(collections, 'Generator'): + self.assertIsSubclass(G, collections.Generator) + self.assertIsSubclass(G, collections.Iterable) + self.assertNotIsSubclass(type(g), G) + + def test_subclassing_subclasshook(self): + + class Base(typing.Iterable): + @classmethod + def __subclasshook__(cls, other): + if other.__name__ == 'Foo': + return True + else: + return False + + class C(Base): ... + class Foo: ... + class Bar: ... + self.assertIsSubclass(Foo, Base) + self.assertIsSubclass(Foo, C) + self.assertNotIsSubclass(Bar, C) + + def test_subclassing_register(self): + + class A(typing.Container): ... + class B(A): ... + + class C: ... + A.register(C) + self.assertIsSubclass(C, A) + self.assertNotIsSubclass(C, B) + + class D: ... + B.register(D) + self.assertIsSubclass(D, A) + self.assertIsSubclass(D, B) + + class M(): ... + collections.MutableMapping.register(M) + self.assertIsSubclass(M, typing.Mapping) + + def test_collections_as_base(self): + + class M(collections.Mapping): ... + self.assertIsSubclass(M, typing.Mapping) + self.assertIsSubclass(M, typing.Iterable) + + class S(collections.MutableSequence): ... + self.assertIsSubclass(S, typing.MutableSequence) + self.assertIsSubclass(S, typing.Iterable) + + class I(collections.Iterable): ... + self.assertIsSubclass(I, typing.Iterable) + + class A(collections.Mapping, metaclass=abc.ABCMeta): ... + class B: ... + A.register(B) + self.assertIsSubclass(B, typing.Mapping) + class OtherABCTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -993,7 +993,10 @@ # This allows unparameterized generic collections to be used # with issubclass() and isinstance() in the same way as their # collections.abc counterparts (e.g., isinstance([], Iterable)). - self.__subclasshook__ = _make_subclasshook(self) + if ('__subclasshook__' not in namespace and extra # allow overriding + or hasattr(self.__subclasshook__, '__name__') and + self.__subclasshook__.__name__ == '__extrahook__'): + self.__subclasshook__ = _make_subclasshook(self) if isinstance(extra, abc.ABCMeta): self._abc_registry = extra._abc_registry return self -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 8 23:28:38 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 03:28:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_further_typing=2Epy_changes_from_upstream=2E_=28me?= =?utf-8?b?cmdlIDMuNi0+My43KQ==?= Message-ID: <20161009032838.79425.93705.41DC23F9@psf.io> https://hg.python.org/cpython/rev/e51ef450238b changeset: 104405:e51ef450238b parent: 104402:e5f5eae344d4 parent: 104404:5fd1db0266d4 user: Guido van Rossum date: Sat Oct 08 20:28:16 2016 -0700 summary: Merge further typing.py changes from upstream. (merge 3.6->3.7) files: Lib/test/test_typing.py | 79 +++++++++++++++++++++++++++++ Lib/typing.py | 5 +- 2 files changed, 83 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -20,6 +20,7 @@ from typing import NamedTuple from typing import IO, TextIO, BinaryIO from typing import Pattern, Match +import abc import typing try: import collections.abc as collections_abc @@ -1385,6 +1386,8 @@ return 0 self.assertEqual(len(MMC()), 0) + assert callable(MMC.update) + self.assertIsInstance(MMC(), typing.Mapping) class MMB(typing.MutableMapping[KT, VT]): def __getitem__(self, k): @@ -1409,6 +1412,82 @@ self.assertIsSubclass(MMB, typing.Mapping) self.assertIsSubclass(MMC, typing.Mapping) + self.assertIsInstance(MMB[KT, VT](), typing.Mapping) + self.assertIsInstance(MMB[KT, VT](), collections.Mapping) + + self.assertIsSubclass(MMA, collections.Mapping) + self.assertIsSubclass(MMB, collections.Mapping) + self.assertIsSubclass(MMC, collections.Mapping) + + self.assertIsSubclass(MMB[str, str], typing.Mapping) + self.assertIsSubclass(MMC, MMA) + + class I(typing.Iterable): ... + self.assertNotIsSubclass(list, I) + + class G(typing.Generator[int, int, int]): ... + def g(): yield 0 + self.assertIsSubclass(G, typing.Generator) + self.assertIsSubclass(G, typing.Iterable) + if hasattr(collections, 'Generator'): + self.assertIsSubclass(G, collections.Generator) + self.assertIsSubclass(G, collections.Iterable) + self.assertNotIsSubclass(type(g), G) + + def test_subclassing_subclasshook(self): + + class Base(typing.Iterable): + @classmethod + def __subclasshook__(cls, other): + if other.__name__ == 'Foo': + return True + else: + return False + + class C(Base): ... + class Foo: ... + class Bar: ... + self.assertIsSubclass(Foo, Base) + self.assertIsSubclass(Foo, C) + self.assertNotIsSubclass(Bar, C) + + def test_subclassing_register(self): + + class A(typing.Container): ... + class B(A): ... + + class C: ... + A.register(C) + self.assertIsSubclass(C, A) + self.assertNotIsSubclass(C, B) + + class D: ... + B.register(D) + self.assertIsSubclass(D, A) + self.assertIsSubclass(D, B) + + class M(): ... + collections.MutableMapping.register(M) + self.assertIsSubclass(M, typing.Mapping) + + def test_collections_as_base(self): + + class M(collections.Mapping): ... + self.assertIsSubclass(M, typing.Mapping) + self.assertIsSubclass(M, typing.Iterable) + + class S(collections.MutableSequence): ... + self.assertIsSubclass(S, typing.MutableSequence) + self.assertIsSubclass(S, typing.Iterable) + + class I(collections.Iterable): ... + self.assertIsSubclass(I, typing.Iterable) + + class A(collections.Mapping, metaclass=abc.ABCMeta): ... + class B: ... + A.register(B) + self.assertIsSubclass(B, typing.Mapping) + class OtherABCTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -993,7 +993,10 @@ # This allows unparameterized generic collections to be used # with issubclass() and isinstance() in the same way as their # collections.abc counterparts (e.g., isinstance([], Iterable)). - self.__subclasshook__ = _make_subclasshook(self) + if ('__subclasshook__' not in namespace and extra # allow overriding + or hasattr(self.__subclasshook__, '__name__') and + self.__subclasshook__.__name__ == '__extrahook__'): + self.__subclasshook__ = _make_subclasshook(self) if isinstance(extra, abc.ABCMeta): self._abc_registry = extra._abc_registry return self -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 01:51:46 2016 From: python-checkins at python.org (inada.naoki) Date: Sun, 09 Oct 2016 05:51:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI2ODAx?= =?utf-8?q?=3A_Added_C_implementation_of_asyncio=2EFuture=2E?= Message-ID: <20161009055146.79323.20331.3A2CEB6A@psf.io> https://hg.python.org/cpython/rev/678424183b38 changeset: 104406:678424183b38 branch: 3.6 parent: 104404:5fd1db0266d4 user: INADA Naoki date: Sun Oct 09 14:44:47 2016 +0900 summary: Issue #26801: Added C implementation of asyncio.Future. Original patch by Yury Selivanov. files: Lib/asyncio/futures.py | 94 +- Misc/NEWS | 3 + Modules/Setup.dist | 1 + Modules/_futuresmodule.c | 1034 ++++++++++++++++ PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + setup.py | 2 + 7 files changed, 1101 insertions(+), 37 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -120,6 +120,46 @@ return getattr(obj, '_asyncio_future_blocking', None) is not None +def _format_callbacks(cb): + """helper function for Future.__repr__""" + size = len(cb) + if not size: + cb = '' + + def format_cb(callback): + return events._format_callback_source(callback, ()) + + if size == 1: + cb = format_cb(cb[0]) + elif size == 2: + cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) + elif size > 2: + cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), + size-2, + format_cb(cb[-1])) + return 'cb=[%s]' % cb + + +def _future_repr_info(future): + # (Future) -> str + """helper function for Future.__repr__""" + info = [future._state.lower()] + if future._state == _FINISHED: + if future._exception is not None: + info.append('exception={!r}'.format(future._exception)) + else: + # use reprlib to limit the length of the output, especially + # for very long strings + result = reprlib.repr(future._result) + info.append('result={}'.format(result)) + if future._callbacks: + info.append(_format_callbacks(future._callbacks)) + if future._source_traceback: + frame = future._source_traceback[-1] + info.append('created at %s:%s' % (frame[0], frame[1])) + return info + + class Future: """This class is *almost* compatible with concurrent.futures.Future. @@ -172,45 +212,10 @@ if self._loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) - def __format_callbacks(self): - cb = self._callbacks - size = len(cb) - if not size: - cb = '' - - def format_cb(callback): - return events._format_callback_source(callback, ()) - - if size == 1: - cb = format_cb(cb[0]) - elif size == 2: - cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) - elif size > 2: - cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), - size-2, - format_cb(cb[-1])) - return 'cb=[%s]' % cb - - def _repr_info(self): - info = [self._state.lower()] - if self._state == _FINISHED: - if self._exception is not None: - info.append('exception={!r}'.format(self._exception)) - else: - # use reprlib to limit the length of the output, especially - # for very long strings - result = reprlib.repr(self._result) - info.append('result={}'.format(result)) - if self._callbacks: - info.append(self.__format_callbacks()) - if self._source_traceback: - frame = self._source_traceback[-1] - info.append('created at %s:%s' % (frame[0], frame[1])) - return info + _repr_info = _future_repr_info def __repr__(self): - info = self._repr_info() - return '<%s %s>' % (self.__class__.__name__, ' '.join(info)) + return '<%s %s>' % (self.__class__.__name__, ' '.join(self._repr_info())) # On Python 3.3 and older, objects with a destructor part of a reference # cycle are never destroyed. It's not more the case on Python 3.4 thanks @@ -426,6 +431,21 @@ dest.set_result(result) +try: + import _futures +except ImportError: + pass +else: + _futures._init_module( + traceback.extract_stack, + events.get_event_loop, + _future_repr_info, + InvalidStateError, + CancelledError) + + Future = _futures.Future + + def _chain_future(source, destination): """Chain two futures so that when one completes, so does the other. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #26801: Added C implementation of asyncio.Future. + Original patch by Yury Selivanov. + - Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). Patch by Xiang Zhang. diff --git a/Modules/Setup.dist b/Modules/Setup.dist --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -181,6 +181,7 @@ #_datetime _datetimemodule.c # datetime accelerator #_bisect _bisectmodule.c # Bisection algorithms #_heapq _heapqmodule.c # Heap queue algorithm +#_futures _futuresmodule.c # Fast asyncio Future #unicodedata unicodedata.c # static Unicode character database diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c new file mode 100644 --- /dev/null +++ b/Modules/_futuresmodule.c @@ -0,0 +1,1034 @@ +#include "Python.h" +#include "structmember.h" + + +/* identifiers used from some functions */ +_Py_IDENTIFIER(call_soon); + + +/* State of the _futures module */ +static int _futuremod_ready; +static PyObject *traceback_extract_stack; +static PyObject *asyncio_get_event_loop; +static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_InvalidStateError; +static PyObject *asyncio_CancelledError; + + +/* Get FutureIter from Future */ +static PyObject* new_future_iter(PyObject *fut); + + +/* make sure module state is initialized and ready to be used. */ +static int +_FuturesMod_EnsureState(void) +{ + if (!_futuremod_ready) { + PyErr_SetString(PyExc_RuntimeError, + "_futures module wasn't properly initialized"); + return -1; + } + return 0; +} + + +typedef enum { + STATE_PENDING, + STATE_CANCELLED, + STATE_FINISHED +} fut_state; + + +typedef struct { + PyObject_HEAD + PyObject *fut_loop; + PyObject *fut_callbacks; + PyObject *fut_exception; + PyObject *fut_result; + PyObject *fut_source_tb; + fut_state fut_state; + int fut_log_tb; + int fut_blocking; + PyObject *dict; + PyObject *fut_weakreflist; +} FutureObj; + + +static int +_schedule_callbacks(FutureObj *fut) +{ + Py_ssize_t len; + PyObject* iters; + int i; + + if (fut->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); + return -1; + } + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return 0; + } + + iters = PyList_GetSlice(fut->fut_callbacks, 0, len); + if (iters == NULL) { + return -1; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { + Py_DECREF(iters); + return -1; + } + + for (i = 0; i < len; i++) { + PyObject *handle = NULL; + PyObject *cb = PyList_GET_ITEM(iters, i); + + handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); + + if (handle == NULL) { + Py_DECREF(iters); + return -1; + } + else { + Py_DECREF(handle); + } + } + + Py_DECREF(iters); + return 0; +} + +static int +FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"loop", NULL}; + PyObject *loop = NULL; + PyObject *res = NULL; + _Py_IDENTIFIER(get_debug); + + if (_FuturesMod_EnsureState()) { + return -1; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { + return -1; + } + if (loop == NULL || loop == Py_None) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return -1; + } + } + else { + Py_INCREF(loop); + } + Py_CLEAR(fut->fut_loop); + fut->fut_loop = loop; + + res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); + if (res == NULL) { + return -1; + } + if (PyObject_IsTrue(res)) { + Py_CLEAR(res); + fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); + if (fut->fut_source_tb == NULL) { + return -1; + } + } + else { + Py_CLEAR(res); + } + + fut->fut_callbacks = PyList_New(0); + if (fut->fut_callbacks == NULL) { + return -1; + } + return 0; +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +PyDoc_STRVAR(pydoc_result, + "Return the result this future represents.\n" + "\n" + "If the future has been cancelled, raises CancelledError. If the\n" + "future's result isn't yet available, raises InvalidStateError. If\n" + "the future is done and has an exception set, this exception is raised." +); + +static PyObject * +FutureObj_result(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + PyObject *type = NULL; + type = PyExceptionInstance_Class(fut->fut_exception); + PyErr_SetObject(type, fut->fut_exception); + return NULL; + } + + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +PyDoc_STRVAR(pydoc_exception, + "Return the exception that was set on this future.\n" + "\n" + "The exception (or None if no exception was set) is returned only if\n" + "the future is done. If the future has been cancelled, raises\n" + "CancelledError. If the future isn't done yet, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_exception(FutureObj *fut, PyObject *arg) +{ + if (_FuturesMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (fut->fut_exception != NULL) { + fut->fut_log_tb = 0; + Py_INCREF(fut->fut_exception); + return fut->fut_exception; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_result, + "Mark the future done and set its result.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_result(FutureObj *fut, PyObject *res) +{ + if (_FuturesMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + Py_INCREF(res); + fut->fut_result = res; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_exception, + "Mark the future done and set an exception.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_exception(FutureObj *fut, PyObject *exc) +{ + PyObject *exc_val = NULL; + + if (_FuturesMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + if (PyExceptionClass_Check(exc)) { + exc_val = PyObject_CallObject(exc, NULL); + if (exc_val == NULL) { + return NULL; + } + } + else { + exc_val = exc; + Py_INCREF(exc_val); + } + if (!PyExceptionInstance_Check(exc_val)) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, "invalid exception object"); + return NULL; + } + if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, + "StopIteration interacts badly with generators " + "and cannot be raised into a Future"); + return NULL; + } + + fut->fut_exception = exc_val; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + fut->fut_log_tb = 1; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_add_done_callback, + "Add a callback to be run when the future becomes done.\n" + "\n" + "The callback is called with a single argument - the future object. If\n" + "the future is already done when this is called, the callback is\n" + "scheduled with call_soon."; +); + +static PyObject * +FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + PyObject *handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); + + if (handle == NULL) { + return NULL; + } + else { + Py_DECREF(handle); + } + } + else { + int err = PyList_Append(fut->fut_callbacks, arg); + if (err != 0) { + return NULL; + } + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_remove_done_callback, + "Remove all instances of a callback from the \"call when done\" list.\n" + "\n" + "Returns the number of callbacks removed." +); + +static PyObject * +FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +{ + PyObject *newlist; + Py_ssize_t len, i, j=0; + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return PyLong_FromSsize_t(0); + } + + newlist = PyList_New(len); + if (newlist == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + int ret; + PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + + if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + goto fail; + } + if (ret == 0) { + Py_INCREF(item); + PyList_SET_ITEM(newlist, j, item); + j++; + } + } + + if (PyList_SetSlice(newlist, j, len, NULL) < 0) { + goto fail; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + goto fail; + } + Py_DECREF(newlist); + return PyLong_FromSsize_t(len - j); + +fail: + Py_DECREF(newlist); + return NULL; +} + +PyDoc_STRVAR(pydoc_cancel, + "Cancel the future and schedule callbacks.\n" + "\n" + "If the future is already done or cancelled, return False. Otherwise,\n" + "change the future's state to cancelled, schedule the callbacks and\n" + "return True." +); + +static PyObject * +FutureObj_cancel(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); + +static PyObject * +FutureObj_cancelled(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(pydoc_done, + "Return True if the future is done.\n" + "\n" + "Done means either that a result / exception are available, or that the\n" + "future was cancelled." +); + +static PyObject * +FutureObj_done(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_PENDING) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject * +FutureObj_get_blocking(FutureObj *fut) +{ + if (fut->fut_blocking) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static int +FutureObj_set_blocking(FutureObj *fut, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; + } + fut->fut_blocking = is_true; + return 0; +} + +static PyObject * +FutureObj_get_log_traceback(FutureObj *fut) +{ + if (fut->fut_log_tb) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +FutureObj_get_loop(FutureObj *fut) +{ + if (fut->fut_loop == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_loop); + return fut->fut_loop; +} + +static PyObject * +FutureObj_get_callbacks(FutureObj *fut) +{ + if (fut->fut_callbacks == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_callbacks); + return fut->fut_callbacks; +} + +static PyObject * +FutureObj_get_result(FutureObj *fut) +{ + if (fut->fut_result == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +static PyObject * +FutureObj_get_exception(FutureObj *fut) +{ + if (fut->fut_exception == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_exception); + return fut->fut_exception; +} + +static PyObject * +FutureObj_get_source_traceback(FutureObj *fut) +{ + if (fut->fut_source_tb == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_source_tb); + return fut->fut_source_tb; +} + +static PyObject * +FutureObj_get_state(FutureObj *fut) +{ + _Py_IDENTIFIER(PENDING); + _Py_IDENTIFIER(CANCELLED); + _Py_IDENTIFIER(FINISHED); + PyObject *ret = NULL; + + switch (fut->fut_state) { + case STATE_PENDING: + ret = _PyUnicode_FromId(&PyId_PENDING); + break; + case STATE_CANCELLED: + ret = _PyUnicode_FromId(&PyId_CANCELLED); + break; + case STATE_FINISHED: + ret = _PyUnicode_FromId(&PyId_FINISHED); + break; + default: + assert (0); + } + Py_INCREF(ret); + return ret; +} + +static PyObject* +FutureObj__repr_info(FutureObj *fut) +{ + if (asyncio_repr_info_func == NULL) { + return PyList_New(0); + } + return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); +} + +static PyObject * +FutureObj_repr(FutureObj *fut) +{ + _Py_IDENTIFIER(_repr_info); + + PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed + if (_repr_info == NULL) { + return NULL; + } + + PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, + NULL); + if (rinfo == NULL) { + return NULL; + } + + PyObject *sp = PyUnicode_FromString(" "); + if (sp == NULL) { + Py_DECREF(rinfo); + return NULL; + } + + PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); + Py_DECREF(sp); + Py_DECREF(rinfo); + if (rinfo_s == NULL) { + return NULL; + } + + PyObject *rstr = NULL; + PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), + "__name__"); + if (type_name != NULL) { + rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); + Py_DECREF(type_name); + } + Py_DECREF(rinfo_s); + return rstr; +} + +static void +FutureObj_finalize(FutureObj *fut) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(exception); + _Py_IDENTIFIER(future); + _Py_IDENTIFIER(source_traceback); + + if (!fut->fut_log_tb) { + return; + } + assert(fut->fut_exception != NULL); + fut->fut_log_tb = 0;; + + PyObject *error_type, *error_value, *error_traceback; + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyObject *context = NULL; + PyObject *type_name = NULL; + PyObject *message = NULL; + PyObject *func = NULL; + PyObject *res = NULL; + + context = PyDict_New(); + if (context == NULL) { + goto finally; + } + + type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); + if (type_name == NULL) { + goto finally; + } + + message = PyUnicode_FromFormat( + "%S exception was never retrieved", type_name); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || + _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { + goto finally; + } + if (fut->fut_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + fut->fut_source_tb) < 0) { + goto finally; + } + } + + func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(type_name); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + + +static PyAsyncMethods FutureType_as_async = { + (unaryfunc)new_future_iter, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef FutureType_methods[] = { + {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, + {"add_done_callback", + (PyCFunction)FutureObj_add_done_callback, + METH_O, pydoc_add_done_callback}, + {"remove_done_callback", + (PyCFunction)FutureObj_remove_done_callback, + METH_O, pydoc_remove_done_callback}, + {"set_result", + (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, + {"set_exception", + (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, + {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, + {"cancelled", + (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, + {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, + {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, + {"exception", + (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef FutureType_getsetlist[] = { + {"_state", (getter)FutureObj_get_state, NULL, NULL}, + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, + (setter)FutureObj_set_blocking, NULL}, + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, + {"_result", (getter)FutureObj_get_result, NULL, NULL}, + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static void FutureObj_dealloc(PyObject *self); + +static PyTypeObject FutureType = { + PyVarObject_HEAD_INIT(0, 0) + "_futures.Future", + sizeof(FutureObj), /* tp_basicsize */ + .tp_dealloc = FutureObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = "Fast asyncio.Future implementation.", + .tp_traverse = (traverseproc)FutureObj_traverse, + .tp_clear = (inquiry)FutureObj_clear, + .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), + .tp_iter = (getiterfunc)new_future_iter, + .tp_methods = FutureType_methods, + .tp_getset = FutureType_getsetlist, + .tp_dictoffset = offsetof(FutureObj, dict), + .tp_init = (initproc)FutureObj_init, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)FutureObj_finalize, +}; + +static void +FutureObj_dealloc(PyObject *self) +{ + FutureObj *fut = (FutureObj *)self; + + if (Py_TYPE(fut) == &FutureType) { + /* When fut is subclass of Future, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (fut->fut_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + FutureObj_clear(fut); + Py_TYPE(fut)->tp_free(fut); +} + + +/*********************** Future Iterator **************************/ + +typedef struct { + PyObject_HEAD + FutureObj *future; +} futureiterobject; + +static void +FutureIter_dealloc(futureiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->future); + PyObject_GC_Del(it); +} + +static PyObject * +FutureIter_iternext(futureiterobject *it) +{ + PyObject *res; + FutureObj *fut = it->future; + + if (fut == NULL) { + return NULL; + } + + if (fut->fut_state == STATE_PENDING) { + if (!fut->fut_blocking) { + fut->fut_blocking = 1; + Py_INCREF(fut); + return (PyObject *)fut; + } + PyErr_Format(PyExc_AssertionError, + "yield from wasn't used with future"); + return NULL; + } + + res = FutureObj_result(fut, NULL); + if (res != NULL) { + // normal result + PyErr_SetObject(PyExc_StopIteration, res); + Py_DECREF(res); + } + + it->future = NULL; + Py_DECREF(fut); + return NULL; +} + +static PyObject * +FutureIter_send(futureiterobject *self, PyObject *arg) +{ + if (arg != Py_None) { + PyErr_Format(PyExc_TypeError, + "can't send non-None value to a FutureIter"); + return NULL; + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_throw(futureiterobject *self, PyObject *args) +{ + PyObject *type=NULL, *val=NULL, *tb=NULL; + if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) + return NULL; + + if (val == Py_None) { + val = NULL; + } + if (tb == Py_None) { + tb = NULL; + } + + Py_CLEAR(self->future); + + if (tb != NULL) { + PyErr_Restore(type, val, tb); + } + else if (val != NULL) { + PyErr_SetObject(type, val); + } + else { + if (PyExceptionClass_Check(type)) { + val = PyObject_CallObject(type, NULL); + } + else { + val = type; + assert (PyExceptionInstance_Check(val)); + type = (PyObject*)Py_TYPE(val); + assert (PyExceptionClass_Check(type)); + } + PyErr_SetObject(type, val); + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_close(futureiterobject *self, PyObject *arg) +{ + Py_CLEAR(self->future); + Py_RETURN_NONE; +} + +static int +FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->future); + return 0; +} + +static PyMethodDef FutureIter_methods[] = { + {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, + {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, + {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, + {NULL, NULL} /* Sentinel */ +}; + +static PyTypeObject FutureIterType = { + PyVarObject_HEAD_INIT(0, 0) + "_futures.FutureIter", + sizeof(futureiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)FutureIter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 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 */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)FutureIter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)FutureIter_iternext, /* tp_iternext */ + FutureIter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +static PyObject * +new_future_iter(PyObject *fut) +{ + futureiterobject *it; + + if (!PyObject_TypeCheck(fut, &FutureType)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(futureiterobject, &FutureIterType); + if (it == NULL) { + return NULL; + } + Py_INCREF(fut); + it->future = (FutureObj*)fut; + _PyObject_GC_TRACK(it); + return (PyObject*)it; +} + +/*********************** Module **************************/ + +PyDoc_STRVAR(module_doc, "Fast asyncio.Future implementation.\n"); + +PyObject * +_init_module(PyObject *self, PyObject *args) +{ + PyObject *extract_stack; + PyObject *get_event_loop; + PyObject *repr_info_func; + PyObject *invalidStateError; + PyObject *cancelledError; + + if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, + &extract_stack, + &get_event_loop, + &repr_info_func, + &invalidStateError, + &cancelledError)) { + return NULL; + } + + Py_INCREF(extract_stack); + Py_XSETREF(traceback_extract_stack, extract_stack); + + Py_INCREF(get_event_loop); + Py_XSETREF(asyncio_get_event_loop, get_event_loop); + + Py_INCREF(repr_info_func); + Py_XSETREF(asyncio_repr_info_func, repr_info_func); + + Py_INCREF(invalidStateError); + Py_XSETREF(asyncio_InvalidStateError, invalidStateError); + + Py_INCREF(cancelledError); + Py_XSETREF(asyncio_CancelledError, cancelledError); + + _futuremod_ready = 1; + + Py_RETURN_NONE; +} + + +static struct PyMethodDef futuresmod_methods[] = { + {"_init_module", _init_module, METH_VARARGS, NULL}, + {NULL, NULL} +}; + + +static struct PyModuleDef _futuresmodule = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_futures", /* m_name */ + module_doc, /* m_doc */ + -1, /* m_size */ + futuresmod_methods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + + +PyMODINIT_FUNC +PyInit__futures(void) +{ + if (PyType_Ready(&FutureType) < 0) { + return NULL; + } + if (PyType_Ready(&FutureIterType) < 0) { + return NULL; + } + + PyObject *m = PyModule_Create(&_futuresmodule); + if (m == NULL) { + return NULL; + } + + Py_INCREF(&FutureType); + if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { + Py_DECREF(&FutureType); + return NULL; + } + + return m; +} diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -221,6 +221,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -470,6 +470,9 @@ Modules + + Modules + Modules diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -656,6 +656,8 @@ depends=['unicodedata_db.h', 'unicodename_db.h']) ) # _opcode module exts.append( Extension('_opcode', ['_opcode.c']) ) + # Fast asyncio Future implementation + exts.append( Extension("_futures", ["_futuresmodule.c"]) ) # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 01:51:46 2016 From: python-checkins at python.org (inada.naoki) Date: Sun, 09 Oct 2016 05:51:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326801=3A_Added_C_implementation_of_asyncio=2EFu?= =?utf-8?q?ture=2E?= Message-ID: <20161009055146.17363.81428.50E87106@psf.io> https://hg.python.org/cpython/rev/f8815001a390 changeset: 104407:f8815001a390 parent: 104405:e51ef450238b parent: 104406:678424183b38 user: INADA Naoki date: Sun Oct 09 14:51:36 2016 +0900 summary: Issue #26801: Added C implementation of asyncio.Future. Original patch by Yury Selivanov. files: Lib/asyncio/futures.py | 94 +- Misc/NEWS | 3 + Modules/Setup.dist | 1 + Modules/_futuresmodule.c | 1034 ++++++++++++++++ PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + setup.py | 2 + 7 files changed, 1101 insertions(+), 37 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -120,6 +120,46 @@ return getattr(obj, '_asyncio_future_blocking', None) is not None +def _format_callbacks(cb): + """helper function for Future.__repr__""" + size = len(cb) + if not size: + cb = '' + + def format_cb(callback): + return events._format_callback_source(callback, ()) + + if size == 1: + cb = format_cb(cb[0]) + elif size == 2: + cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) + elif size > 2: + cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), + size-2, + format_cb(cb[-1])) + return 'cb=[%s]' % cb + + +def _future_repr_info(future): + # (Future) -> str + """helper function for Future.__repr__""" + info = [future._state.lower()] + if future._state == _FINISHED: + if future._exception is not None: + info.append('exception={!r}'.format(future._exception)) + else: + # use reprlib to limit the length of the output, especially + # for very long strings + result = reprlib.repr(future._result) + info.append('result={}'.format(result)) + if future._callbacks: + info.append(_format_callbacks(future._callbacks)) + if future._source_traceback: + frame = future._source_traceback[-1] + info.append('created at %s:%s' % (frame[0], frame[1])) + return info + + class Future: """This class is *almost* compatible with concurrent.futures.Future. @@ -172,45 +212,10 @@ if self._loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) - def __format_callbacks(self): - cb = self._callbacks - size = len(cb) - if not size: - cb = '' - - def format_cb(callback): - return events._format_callback_source(callback, ()) - - if size == 1: - cb = format_cb(cb[0]) - elif size == 2: - cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) - elif size > 2: - cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), - size-2, - format_cb(cb[-1])) - return 'cb=[%s]' % cb - - def _repr_info(self): - info = [self._state.lower()] - if self._state == _FINISHED: - if self._exception is not None: - info.append('exception={!r}'.format(self._exception)) - else: - # use reprlib to limit the length of the output, especially - # for very long strings - result = reprlib.repr(self._result) - info.append('result={}'.format(result)) - if self._callbacks: - info.append(self.__format_callbacks()) - if self._source_traceback: - frame = self._source_traceback[-1] - info.append('created at %s:%s' % (frame[0], frame[1])) - return info + _repr_info = _future_repr_info def __repr__(self): - info = self._repr_info() - return '<%s %s>' % (self.__class__.__name__, ' '.join(info)) + return '<%s %s>' % (self.__class__.__name__, ' '.join(self._repr_info())) # On Python 3.3 and older, objects with a destructor part of a reference # cycle are never destroyed. It's not more the case on Python 3.4 thanks @@ -426,6 +431,21 @@ dest.set_result(result) +try: + import _futures +except ImportError: + pass +else: + _futures._init_module( + traceback.extract_stack, + events.get_event_loop, + _future_repr_info, + InvalidStateError, + CancelledError) + + Future = _futures.Future + + def _chain_future(source, destination): """Chain two futures so that when one completes, so does the other. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #26801: Added C implementation of asyncio.Future. + Original patch by Yury Selivanov. + - Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). Patch by Xiang Zhang. diff --git a/Modules/Setup.dist b/Modules/Setup.dist --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -181,6 +181,7 @@ #_datetime _datetimemodule.c # datetime accelerator #_bisect _bisectmodule.c # Bisection algorithms #_heapq _heapqmodule.c # Heap queue algorithm +#_futures _futuresmodule.c # Fast asyncio Future #unicodedata unicodedata.c # static Unicode character database diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c new file mode 100644 --- /dev/null +++ b/Modules/_futuresmodule.c @@ -0,0 +1,1034 @@ +#include "Python.h" +#include "structmember.h" + + +/* identifiers used from some functions */ +_Py_IDENTIFIER(call_soon); + + +/* State of the _futures module */ +static int _futuremod_ready; +static PyObject *traceback_extract_stack; +static PyObject *asyncio_get_event_loop; +static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_InvalidStateError; +static PyObject *asyncio_CancelledError; + + +/* Get FutureIter from Future */ +static PyObject* new_future_iter(PyObject *fut); + + +/* make sure module state is initialized and ready to be used. */ +static int +_FuturesMod_EnsureState(void) +{ + if (!_futuremod_ready) { + PyErr_SetString(PyExc_RuntimeError, + "_futures module wasn't properly initialized"); + return -1; + } + return 0; +} + + +typedef enum { + STATE_PENDING, + STATE_CANCELLED, + STATE_FINISHED +} fut_state; + + +typedef struct { + PyObject_HEAD + PyObject *fut_loop; + PyObject *fut_callbacks; + PyObject *fut_exception; + PyObject *fut_result; + PyObject *fut_source_tb; + fut_state fut_state; + int fut_log_tb; + int fut_blocking; + PyObject *dict; + PyObject *fut_weakreflist; +} FutureObj; + + +static int +_schedule_callbacks(FutureObj *fut) +{ + Py_ssize_t len; + PyObject* iters; + int i; + + if (fut->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); + return -1; + } + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return 0; + } + + iters = PyList_GetSlice(fut->fut_callbacks, 0, len); + if (iters == NULL) { + return -1; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { + Py_DECREF(iters); + return -1; + } + + for (i = 0; i < len; i++) { + PyObject *handle = NULL; + PyObject *cb = PyList_GET_ITEM(iters, i); + + handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); + + if (handle == NULL) { + Py_DECREF(iters); + return -1; + } + else { + Py_DECREF(handle); + } + } + + Py_DECREF(iters); + return 0; +} + +static int +FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"loop", NULL}; + PyObject *loop = NULL; + PyObject *res = NULL; + _Py_IDENTIFIER(get_debug); + + if (_FuturesMod_EnsureState()) { + return -1; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { + return -1; + } + if (loop == NULL || loop == Py_None) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return -1; + } + } + else { + Py_INCREF(loop); + } + Py_CLEAR(fut->fut_loop); + fut->fut_loop = loop; + + res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); + if (res == NULL) { + return -1; + } + if (PyObject_IsTrue(res)) { + Py_CLEAR(res); + fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); + if (fut->fut_source_tb == NULL) { + return -1; + } + } + else { + Py_CLEAR(res); + } + + fut->fut_callbacks = PyList_New(0); + if (fut->fut_callbacks == NULL) { + return -1; + } + return 0; +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +PyDoc_STRVAR(pydoc_result, + "Return the result this future represents.\n" + "\n" + "If the future has been cancelled, raises CancelledError. If the\n" + "future's result isn't yet available, raises InvalidStateError. If\n" + "the future is done and has an exception set, this exception is raised." +); + +static PyObject * +FutureObj_result(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + PyObject *type = NULL; + type = PyExceptionInstance_Class(fut->fut_exception); + PyErr_SetObject(type, fut->fut_exception); + return NULL; + } + + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +PyDoc_STRVAR(pydoc_exception, + "Return the exception that was set on this future.\n" + "\n" + "The exception (or None if no exception was set) is returned only if\n" + "the future is done. If the future has been cancelled, raises\n" + "CancelledError. If the future isn't done yet, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_exception(FutureObj *fut, PyObject *arg) +{ + if (_FuturesMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (fut->fut_exception != NULL) { + fut->fut_log_tb = 0; + Py_INCREF(fut->fut_exception); + return fut->fut_exception; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_result, + "Mark the future done and set its result.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_result(FutureObj *fut, PyObject *res) +{ + if (_FuturesMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + Py_INCREF(res); + fut->fut_result = res; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_exception, + "Mark the future done and set an exception.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_exception(FutureObj *fut, PyObject *exc) +{ + PyObject *exc_val = NULL; + + if (_FuturesMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + if (PyExceptionClass_Check(exc)) { + exc_val = PyObject_CallObject(exc, NULL); + if (exc_val == NULL) { + return NULL; + } + } + else { + exc_val = exc; + Py_INCREF(exc_val); + } + if (!PyExceptionInstance_Check(exc_val)) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, "invalid exception object"); + return NULL; + } + if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, + "StopIteration interacts badly with generators " + "and cannot be raised into a Future"); + return NULL; + } + + fut->fut_exception = exc_val; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + fut->fut_log_tb = 1; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_add_done_callback, + "Add a callback to be run when the future becomes done.\n" + "\n" + "The callback is called with a single argument - the future object. If\n" + "the future is already done when this is called, the callback is\n" + "scheduled with call_soon."; +); + +static PyObject * +FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + PyObject *handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); + + if (handle == NULL) { + return NULL; + } + else { + Py_DECREF(handle); + } + } + else { + int err = PyList_Append(fut->fut_callbacks, arg); + if (err != 0) { + return NULL; + } + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_remove_done_callback, + "Remove all instances of a callback from the \"call when done\" list.\n" + "\n" + "Returns the number of callbacks removed." +); + +static PyObject * +FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +{ + PyObject *newlist; + Py_ssize_t len, i, j=0; + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return PyLong_FromSsize_t(0); + } + + newlist = PyList_New(len); + if (newlist == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + int ret; + PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + + if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + goto fail; + } + if (ret == 0) { + Py_INCREF(item); + PyList_SET_ITEM(newlist, j, item); + j++; + } + } + + if (PyList_SetSlice(newlist, j, len, NULL) < 0) { + goto fail; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + goto fail; + } + Py_DECREF(newlist); + return PyLong_FromSsize_t(len - j); + +fail: + Py_DECREF(newlist); + return NULL; +} + +PyDoc_STRVAR(pydoc_cancel, + "Cancel the future and schedule callbacks.\n" + "\n" + "If the future is already done or cancelled, return False. Otherwise,\n" + "change the future's state to cancelled, schedule the callbacks and\n" + "return True." +); + +static PyObject * +FutureObj_cancel(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); + +static PyObject * +FutureObj_cancelled(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(pydoc_done, + "Return True if the future is done.\n" + "\n" + "Done means either that a result / exception are available, or that the\n" + "future was cancelled." +); + +static PyObject * +FutureObj_done(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_PENDING) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject * +FutureObj_get_blocking(FutureObj *fut) +{ + if (fut->fut_blocking) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static int +FutureObj_set_blocking(FutureObj *fut, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; + } + fut->fut_blocking = is_true; + return 0; +} + +static PyObject * +FutureObj_get_log_traceback(FutureObj *fut) +{ + if (fut->fut_log_tb) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +FutureObj_get_loop(FutureObj *fut) +{ + if (fut->fut_loop == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_loop); + return fut->fut_loop; +} + +static PyObject * +FutureObj_get_callbacks(FutureObj *fut) +{ + if (fut->fut_callbacks == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_callbacks); + return fut->fut_callbacks; +} + +static PyObject * +FutureObj_get_result(FutureObj *fut) +{ + if (fut->fut_result == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +static PyObject * +FutureObj_get_exception(FutureObj *fut) +{ + if (fut->fut_exception == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_exception); + return fut->fut_exception; +} + +static PyObject * +FutureObj_get_source_traceback(FutureObj *fut) +{ + if (fut->fut_source_tb == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_source_tb); + return fut->fut_source_tb; +} + +static PyObject * +FutureObj_get_state(FutureObj *fut) +{ + _Py_IDENTIFIER(PENDING); + _Py_IDENTIFIER(CANCELLED); + _Py_IDENTIFIER(FINISHED); + PyObject *ret = NULL; + + switch (fut->fut_state) { + case STATE_PENDING: + ret = _PyUnicode_FromId(&PyId_PENDING); + break; + case STATE_CANCELLED: + ret = _PyUnicode_FromId(&PyId_CANCELLED); + break; + case STATE_FINISHED: + ret = _PyUnicode_FromId(&PyId_FINISHED); + break; + default: + assert (0); + } + Py_INCREF(ret); + return ret; +} + +static PyObject* +FutureObj__repr_info(FutureObj *fut) +{ + if (asyncio_repr_info_func == NULL) { + return PyList_New(0); + } + return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); +} + +static PyObject * +FutureObj_repr(FutureObj *fut) +{ + _Py_IDENTIFIER(_repr_info); + + PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed + if (_repr_info == NULL) { + return NULL; + } + + PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, + NULL); + if (rinfo == NULL) { + return NULL; + } + + PyObject *sp = PyUnicode_FromString(" "); + if (sp == NULL) { + Py_DECREF(rinfo); + return NULL; + } + + PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); + Py_DECREF(sp); + Py_DECREF(rinfo); + if (rinfo_s == NULL) { + return NULL; + } + + PyObject *rstr = NULL; + PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), + "__name__"); + if (type_name != NULL) { + rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); + Py_DECREF(type_name); + } + Py_DECREF(rinfo_s); + return rstr; +} + +static void +FutureObj_finalize(FutureObj *fut) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(exception); + _Py_IDENTIFIER(future); + _Py_IDENTIFIER(source_traceback); + + if (!fut->fut_log_tb) { + return; + } + assert(fut->fut_exception != NULL); + fut->fut_log_tb = 0;; + + PyObject *error_type, *error_value, *error_traceback; + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyObject *context = NULL; + PyObject *type_name = NULL; + PyObject *message = NULL; + PyObject *func = NULL; + PyObject *res = NULL; + + context = PyDict_New(); + if (context == NULL) { + goto finally; + } + + type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); + if (type_name == NULL) { + goto finally; + } + + message = PyUnicode_FromFormat( + "%S exception was never retrieved", type_name); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || + _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { + goto finally; + } + if (fut->fut_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + fut->fut_source_tb) < 0) { + goto finally; + } + } + + func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(type_name); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + + +static PyAsyncMethods FutureType_as_async = { + (unaryfunc)new_future_iter, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef FutureType_methods[] = { + {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, + {"add_done_callback", + (PyCFunction)FutureObj_add_done_callback, + METH_O, pydoc_add_done_callback}, + {"remove_done_callback", + (PyCFunction)FutureObj_remove_done_callback, + METH_O, pydoc_remove_done_callback}, + {"set_result", + (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, + {"set_exception", + (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, + {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, + {"cancelled", + (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, + {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, + {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, + {"exception", + (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef FutureType_getsetlist[] = { + {"_state", (getter)FutureObj_get_state, NULL, NULL}, + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, + (setter)FutureObj_set_blocking, NULL}, + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, + {"_result", (getter)FutureObj_get_result, NULL, NULL}, + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static void FutureObj_dealloc(PyObject *self); + +static PyTypeObject FutureType = { + PyVarObject_HEAD_INIT(0, 0) + "_futures.Future", + sizeof(FutureObj), /* tp_basicsize */ + .tp_dealloc = FutureObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = "Fast asyncio.Future implementation.", + .tp_traverse = (traverseproc)FutureObj_traverse, + .tp_clear = (inquiry)FutureObj_clear, + .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), + .tp_iter = (getiterfunc)new_future_iter, + .tp_methods = FutureType_methods, + .tp_getset = FutureType_getsetlist, + .tp_dictoffset = offsetof(FutureObj, dict), + .tp_init = (initproc)FutureObj_init, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)FutureObj_finalize, +}; + +static void +FutureObj_dealloc(PyObject *self) +{ + FutureObj *fut = (FutureObj *)self; + + if (Py_TYPE(fut) == &FutureType) { + /* When fut is subclass of Future, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (fut->fut_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + FutureObj_clear(fut); + Py_TYPE(fut)->tp_free(fut); +} + + +/*********************** Future Iterator **************************/ + +typedef struct { + PyObject_HEAD + FutureObj *future; +} futureiterobject; + +static void +FutureIter_dealloc(futureiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->future); + PyObject_GC_Del(it); +} + +static PyObject * +FutureIter_iternext(futureiterobject *it) +{ + PyObject *res; + FutureObj *fut = it->future; + + if (fut == NULL) { + return NULL; + } + + if (fut->fut_state == STATE_PENDING) { + if (!fut->fut_blocking) { + fut->fut_blocking = 1; + Py_INCREF(fut); + return (PyObject *)fut; + } + PyErr_Format(PyExc_AssertionError, + "yield from wasn't used with future"); + return NULL; + } + + res = FutureObj_result(fut, NULL); + if (res != NULL) { + // normal result + PyErr_SetObject(PyExc_StopIteration, res); + Py_DECREF(res); + } + + it->future = NULL; + Py_DECREF(fut); + return NULL; +} + +static PyObject * +FutureIter_send(futureiterobject *self, PyObject *arg) +{ + if (arg != Py_None) { + PyErr_Format(PyExc_TypeError, + "can't send non-None value to a FutureIter"); + return NULL; + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_throw(futureiterobject *self, PyObject *args) +{ + PyObject *type=NULL, *val=NULL, *tb=NULL; + if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) + return NULL; + + if (val == Py_None) { + val = NULL; + } + if (tb == Py_None) { + tb = NULL; + } + + Py_CLEAR(self->future); + + if (tb != NULL) { + PyErr_Restore(type, val, tb); + } + else if (val != NULL) { + PyErr_SetObject(type, val); + } + else { + if (PyExceptionClass_Check(type)) { + val = PyObject_CallObject(type, NULL); + } + else { + val = type; + assert (PyExceptionInstance_Check(val)); + type = (PyObject*)Py_TYPE(val); + assert (PyExceptionClass_Check(type)); + } + PyErr_SetObject(type, val); + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_close(futureiterobject *self, PyObject *arg) +{ + Py_CLEAR(self->future); + Py_RETURN_NONE; +} + +static int +FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->future); + return 0; +} + +static PyMethodDef FutureIter_methods[] = { + {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, + {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, + {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, + {NULL, NULL} /* Sentinel */ +}; + +static PyTypeObject FutureIterType = { + PyVarObject_HEAD_INIT(0, 0) + "_futures.FutureIter", + sizeof(futureiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)FutureIter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 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 */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)FutureIter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)FutureIter_iternext, /* tp_iternext */ + FutureIter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +static PyObject * +new_future_iter(PyObject *fut) +{ + futureiterobject *it; + + if (!PyObject_TypeCheck(fut, &FutureType)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(futureiterobject, &FutureIterType); + if (it == NULL) { + return NULL; + } + Py_INCREF(fut); + it->future = (FutureObj*)fut; + _PyObject_GC_TRACK(it); + return (PyObject*)it; +} + +/*********************** Module **************************/ + +PyDoc_STRVAR(module_doc, "Fast asyncio.Future implementation.\n"); + +PyObject * +_init_module(PyObject *self, PyObject *args) +{ + PyObject *extract_stack; + PyObject *get_event_loop; + PyObject *repr_info_func; + PyObject *invalidStateError; + PyObject *cancelledError; + + if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, + &extract_stack, + &get_event_loop, + &repr_info_func, + &invalidStateError, + &cancelledError)) { + return NULL; + } + + Py_INCREF(extract_stack); + Py_XSETREF(traceback_extract_stack, extract_stack); + + Py_INCREF(get_event_loop); + Py_XSETREF(asyncio_get_event_loop, get_event_loop); + + Py_INCREF(repr_info_func); + Py_XSETREF(asyncio_repr_info_func, repr_info_func); + + Py_INCREF(invalidStateError); + Py_XSETREF(asyncio_InvalidStateError, invalidStateError); + + Py_INCREF(cancelledError); + Py_XSETREF(asyncio_CancelledError, cancelledError); + + _futuremod_ready = 1; + + Py_RETURN_NONE; +} + + +static struct PyMethodDef futuresmod_methods[] = { + {"_init_module", _init_module, METH_VARARGS, NULL}, + {NULL, NULL} +}; + + +static struct PyModuleDef _futuresmodule = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_futures", /* m_name */ + module_doc, /* m_doc */ + -1, /* m_size */ + futuresmod_methods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + + +PyMODINIT_FUNC +PyInit__futures(void) +{ + if (PyType_Ready(&FutureType) < 0) { + return NULL; + } + if (PyType_Ready(&FutureIterType) < 0) { + return NULL; + } + + PyObject *m = PyModule_Create(&_futuresmodule); + if (m == NULL) { + return NULL; + } + + Py_INCREF(&FutureType); + if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { + Py_DECREF(&FutureType); + return NULL; + } + + return m; +} diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -221,6 +221,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -470,6 +470,9 @@ Modules + + Modules + Modules diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -657,6 +657,8 @@ depends=['unicodedata_db.h', 'unicodename_db.h']) ) # _opcode module exts.append( Extension('_opcode', ['_opcode.c']) ) + # Fast asyncio Future implementation + exts.append( Extension("_futures", ["_futuresmodule.c"]) ) # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 01:54:19 2016 From: python-checkins at python.org (inada.naoki) Date: Sun, 09 Oct 2016 05:54:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Fixed_wrong_is?= =?utf-8?q?sue_number_in_NEWS?= Message-ID: <20161009055419.1522.13848.D91F5F1F@psf.io> https://hg.python.org/cpython/rev/f8d84a3c9e86 changeset: 104408:f8d84a3c9e86 branch: 3.6 parent: 104406:678424183b38 user: INADA Naoki date: Sun Oct 09 14:53:44 2016 +0900 summary: Fixed wrong issue number in NEWS 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 @@ -10,7 +10,7 @@ Core and Builtins ----------------- -- Issue #26801: Added C implementation of asyncio.Future. +- Issue #26081: Added C implementation of asyncio.Future. Original patch by Yury Selivanov. - Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 01:54:20 2016 From: python-checkins at python.org (inada.naoki) Date: Sun, 09 Oct 2016 05:54:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Fixed_wrong_issue_number_in_NEWS?= Message-ID: <20161009055419.20805.47959.22FB6DA3@psf.io> https://hg.python.org/cpython/rev/8ea51c7d985f changeset: 104409:8ea51c7d985f parent: 104407:f8815001a390 parent: 104408:f8d84a3c9e86 user: INADA Naoki date: Sun Oct 09 14:54:12 2016 +0900 summary: Fixed wrong issue number in NEWS 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 @@ -10,7 +10,7 @@ Core and Builtins ----------------- -- Issue #26801: Added C implementation of asyncio.Future. +- Issue #26081: Added C implementation of asyncio.Future. Original patch by Yury Selivanov. - Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 08:38:07 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 09 Oct 2016 12:38:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328379=3A_Removed_?= =?utf-8?q?redundant_check=2E?= Message-ID: <20161009123807.5400.47681.3A1CD324@psf.io> https://hg.python.org/cpython/rev/1be8cd7cee92 changeset: 104410:1be8cd7cee92 user: Serhiy Storchaka date: Sun Oct 09 15:37:43 2016 +0300 summary: Issue #28379: Removed redundant check. Patch by Xiang Zhang. files: Modules/_testcapimodule.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1869,10 +1869,6 @@ return NULL; } - if (PyUnicode_READY(to) < 0) { - return NULL; - } - if (!(to_copy = PyUnicode_New(PyUnicode_GET_LENGTH(to), PyUnicode_MAX_CHAR_VALUE(to)))) { return NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 11:19:14 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 09 Oct 2016 15:19:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328389=3A_Merge_from_3=2E5?= Message-ID: <20161009151914.17616.23831.5EC0E7A5@psf.io> https://hg.python.org/cpython/rev/60c5c77c0190 changeset: 104412:60c5c77c0190 branch: 3.6 parent: 104408:f8d84a3c9e86 parent: 104411:94c9c314f5d9 user: Berker Peksag date: Sun Oct 09 18:18:55 2016 +0300 summary: Issue #28389: Merge from 3.5 files: Doc/library/xmlrpc.client.rst | 36 +++++++++------------- 1 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -568,33 +568,27 @@ print("ERROR", v) To access an XML-RPC server through a HTTP proxy, you need to define a custom -transport. The following example shows how: +transport. The following example shows how:: -.. Example taken from http://lowlife.jp/nobonobo/wiki/xmlrpcwithproxy.html - -:: - - import xmlrpc.client, http.client + import http.client + import xmlrpc.client class ProxiedTransport(xmlrpc.client.Transport): - def set_proxy(self, proxy): - self.proxy = proxy + + def set_proxy(self, host, port=None, headers=None): + self.proxy = host, port + self.proxy_headers = headers def make_connection(self, host): - self.realhost = host - h = http.client.HTTPConnection(self.proxy) - return h + connection = http.client.HTTPConnection(*self.proxy) + connection.set_tunnel(host, headers=self.proxy_headers) + self._connection = host, connection + return connection - def send_request(self, connection, handler, request_body, debug): - connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler)) - - def send_host(self, connection, host): - connection.putheader('Host', self.realhost) - - p = ProxiedTransport() - p.set_proxy('proxy-server:8080') - server = xmlrpc.client.ServerProxy('http://time.xmlrpc.com/RPC2', transport=p) - print(server.currentTime.getCurrentTime()) + transport = ProxiedTransport() + transport.set_proxy('proxy-server', 8080) + server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport) + print(server.examples.getStateName(41)) Example of Client and Server Usage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 11:19:14 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 09 Oct 2016 15:19:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzg5?= =?utf-8?q?=3A_Fix_ProxiedTransport_example_in_xmlrpc=2Eclient_documentati?= =?utf-8?q?on?= Message-ID: <20161009151914.76001.83262.0F4F619B@psf.io> https://hg.python.org/cpython/rev/94c9c314f5d9 changeset: 104411:94c9c314f5d9 branch: 3.5 parent: 104403:7871ec789a27 user: Berker Peksag date: Sun Oct 09 18:18:21 2016 +0300 summary: Issue #28389: Fix ProxiedTransport example in xmlrpc.client documentation files: Doc/library/xmlrpc.client.rst | 36 +++++++++------------- 1 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -555,33 +555,27 @@ print("ERROR", v) To access an XML-RPC server through a HTTP proxy, you need to define a custom -transport. The following example shows how: +transport. The following example shows how:: -.. Example taken from http://lowlife.jp/nobonobo/wiki/xmlrpcwithproxy.html - -:: - - import xmlrpc.client, http.client + import http.client + import xmlrpc.client class ProxiedTransport(xmlrpc.client.Transport): - def set_proxy(self, proxy): - self.proxy = proxy + + def set_proxy(self, host, port=None, headers=None): + self.proxy = host, port + self.proxy_headers = headers def make_connection(self, host): - self.realhost = host - h = http.client.HTTPConnection(self.proxy) - return h + connection = http.client.HTTPConnection(*self.proxy) + connection.set_tunnel(host, headers=self.proxy_headers) + self._connection = host, connection + return connection - def send_request(self, connection, handler, request_body, debug): - connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler)) - - def send_host(self, connection, host): - connection.putheader('Host', self.realhost) - - p = ProxiedTransport() - p.set_proxy('proxy-server:8080') - server = xmlrpc.client.ServerProxy('http://time.xmlrpc.com/RPC2', transport=p) - print(server.currentTime.getCurrentTime()) + transport = ProxiedTransport() + transport.set_proxy('proxy-server', 8080) + server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport) + print(server.examples.getStateName(41)) Example of Client and Server Usage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 11:19:14 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 09 Oct 2016 15:19:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328389=3A_Merge_from_3=2E6?= Message-ID: <20161009151914.15292.53907.162A292C@psf.io> https://hg.python.org/cpython/rev/5f9351bc317e changeset: 104413:5f9351bc317e parent: 104410:1be8cd7cee92 parent: 104412:60c5c77c0190 user: Berker Peksag date: Sun Oct 09 18:19:12 2016 +0300 summary: Issue #28389: Merge from 3.6 files: Doc/library/xmlrpc.client.rst | 36 +++++++++------------- 1 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -568,33 +568,27 @@ print("ERROR", v) To access an XML-RPC server through a HTTP proxy, you need to define a custom -transport. The following example shows how: +transport. The following example shows how:: -.. Example taken from http://lowlife.jp/nobonobo/wiki/xmlrpcwithproxy.html - -:: - - import xmlrpc.client, http.client + import http.client + import xmlrpc.client class ProxiedTransport(xmlrpc.client.Transport): - def set_proxy(self, proxy): - self.proxy = proxy + + def set_proxy(self, host, port=None, headers=None): + self.proxy = host, port + self.proxy_headers = headers def make_connection(self, host): - self.realhost = host - h = http.client.HTTPConnection(self.proxy) - return h + connection = http.client.HTTPConnection(*self.proxy) + connection.set_tunnel(host, headers=self.proxy_headers) + self._connection = host, connection + return connection - def send_request(self, connection, handler, request_body, debug): - connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler)) - - def send_host(self, connection, host): - connection.putheader('Host', self.realhost) - - p = ProxiedTransport() - p.set_proxy('proxy-server:8080') - server = xmlrpc.client.ServerProxy('http://time.xmlrpc.com/RPC2', transport=p) - print(server.currentTime.getCurrentTime()) + transport = ProxiedTransport() + transport.set_proxy('proxy-server', 8080) + server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport) + print(server.examples.getStateName(41)) Example of Client and Server Usage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 12:16:35 2016 From: python-checkins at python.org (yury.selivanov) Date: Sun, 09 Oct 2016 16:16:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2328399=29?= Message-ID: <20161009161635.95017.21664.5C65C921@psf.io> https://hg.python.org/cpython/rev/019c5c2f1239 changeset: 104415:019c5c2f1239 branch: 3.6 parent: 104412:60c5c77c0190 parent: 104414:a3b162d5e70a user: Yury Selivanov date: Sun Oct 09 12:16:08 2016 -0400 summary: Merge 3.5 (issue #28399) files: Lib/asyncio/unix_events.py | 11 ++++++++++ Lib/test/test_asyncio/test_unix_events.py | 12 ++++++---- Misc/NEWS | 3 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -258,6 +258,17 @@ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + # Check for abstract socket. `str` and `bytes` paths are supported. + if path[0] not in (0, '\x00'): + try: + if stat.S_ISSOCK(os.stat(path).st_mode): + os.remove(path) + except FileNotFoundError: + pass + except OSError as err: + # Directory may have permissions only to create socket. + logger.error('Unable to check or remove stale UNIX socket %r: %r', path, err) + try: sock.bind(path) except OSError as exc: diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -241,11 +241,13 @@ with test_utils.unix_socket_path() as path: sock = socket.socket(socket.AF_UNIX) sock.bind(path) - with sock: - coro = self.loop.create_unix_server(lambda: None, path) - with self.assertRaisesRegex(OSError, - 'Address.*is already in use'): - self.loop.run_until_complete(coro) + sock.listen(1) + sock.close() + + coro = self.loop.create_unix_server(lambda: None, path) + srv = self.loop.run_until_complete(coro) + srv.close() + self.loop.run_until_complete(srv.wait_closed()) def test_create_unix_server_existing_path_nonsock(self): with tempfile.NamedTemporaryFile() as file: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -216,6 +216,9 @@ - Issue #28372: Fix asyncio to support formatting of non-python coroutines. +- Issue #28399: Remove UNIX socket from FS before binding. + Patch by ????????? ????. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 12:16:35 2016 From: python-checkins at python.org (yury.selivanov) Date: Sun, 09 Oct 2016 16:16:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjgzOTkp?= Message-ID: <20161009161635.17486.75076.60321677@psf.io> https://hg.python.org/cpython/rev/2e5a8b4d9c97 changeset: 104416:2e5a8b4d9c97 parent: 104413:5f9351bc317e parent: 104415:019c5c2f1239 user: Yury Selivanov date: Sun Oct 09 12:16:26 2016 -0400 summary: Merge 3.6 (issue #28399) files: Lib/asyncio/unix_events.py | 11 ++++++++++ Lib/test/test_asyncio/test_unix_events.py | 12 ++++++---- Misc/NEWS | 3 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -258,6 +258,17 @@ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + # Check for abstract socket. `str` and `bytes` paths are supported. + if path[0] not in (0, '\x00'): + try: + if stat.S_ISSOCK(os.stat(path).st_mode): + os.remove(path) + except FileNotFoundError: + pass + except OSError as err: + # Directory may have permissions only to create socket. + logger.error('Unable to check or remove stale UNIX socket %r: %r', path, err) + try: sock.bind(path) except OSError as exc: diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -241,11 +241,13 @@ with test_utils.unix_socket_path() as path: sock = socket.socket(socket.AF_UNIX) sock.bind(path) - with sock: - coro = self.loop.create_unix_server(lambda: None, path) - with self.assertRaisesRegex(OSError, - 'Address.*is already in use'): - self.loop.run_until_complete(coro) + sock.listen(1) + sock.close() + + coro = self.loop.create_unix_server(lambda: None, path) + srv = self.loop.run_until_complete(coro) + srv.close() + self.loop.run_until_complete(srv.wait_closed()) def test_create_unix_server_existing_path_nonsock(self): with tempfile.NamedTemporaryFile() as file: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -225,6 +225,9 @@ - Issue #28372: Fix asyncio to support formatting of non-python coroutines. +- Issue #28399: Remove UNIX socket from FS before binding. + Patch by ????????? ????. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 12:16:35 2016 From: python-checkins at python.org (yury.selivanov) Date: Sun, 09 Oct 2016 16:16:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzk5?= =?utf-8?q?=3A_Remove_UNIX_socket_from_FS_before_binding=2E?= Message-ID: <20161009161634.85635.92736.CF7CA4CF@psf.io> https://hg.python.org/cpython/rev/a3b162d5e70a changeset: 104414:a3b162d5e70a branch: 3.5 parent: 104411:94c9c314f5d9 user: Yury Selivanov date: Sun Oct 09 12:15:08 2016 -0400 summary: Issue #28399: Remove UNIX socket from FS before binding. Patch by ????????? ????. files: Lib/asyncio/unix_events.py | 11 ++++++++++ Lib/test/test_asyncio/test_unix_events.py | 12 ++++++---- Misc/NEWS | 3 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -258,6 +258,17 @@ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + # Check for abstract socket. `str` and `bytes` paths are supported. + if path[0] not in (0, '\x00'): + try: + if stat.S_ISSOCK(os.stat(path).st_mode): + os.remove(path) + except FileNotFoundError: + pass + except OSError as err: + # Directory may have permissions only to create socket. + logger.error('Unable to check or remove stale UNIX socket %r: %r', path, err) + try: sock.bind(path) except OSError as exc: diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -241,11 +241,13 @@ with test_utils.unix_socket_path() as path: sock = socket.socket(socket.AF_UNIX) sock.bind(path) - with sock: - coro = self.loop.create_unix_server(lambda: None, path) - with self.assertRaisesRegex(OSError, - 'Address.*is already in use'): - self.loop.run_until_complete(coro) + sock.listen(1) + sock.close() + + coro = self.loop.create_unix_server(lambda: None, path) + srv = self.loop.run_until_complete(coro) + srv.close() + self.loop.run_until_complete(srv.wait_closed()) def test_create_unix_server_existing_path_nonsock(self): with tempfile.NamedTemporaryFile() as file: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -385,6 +385,9 @@ - Issue #28372: Fix asyncio to support formatting of non-python coroutines. +- Issue #28399: Remove UNIX socket from FS before binding. + Patch by ????????? ????. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 12:21:19 2016 From: python-checkins at python.org (yury.selivanov) Date: Sun, 09 Oct 2016 16:21:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjc5NzIp?= Message-ID: <20161009162119.19983.15822.2C410C76@psf.io> https://hg.python.org/cpython/rev/47720192b318 changeset: 104419:47720192b318 parent: 104416:2e5a8b4d9c97 parent: 104418:41c4f535b5c0 user: Yury Selivanov date: Sun Oct 09 12:21:03 2016 -0400 summary: Merge 3.6 (issue #27972) files: Lib/asyncio/tasks.py | 21 +++++++++++----- Lib/test/test_asyncio/test_tasks.py | 11 ++++++++ Misc/NEWS | 2 + 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -241,7 +241,7 @@ result = coro.throw(exc) except StopIteration as exc: self.set_result(exc.value) - except futures.CancelledError as exc: + except futures.CancelledError: super().cancel() # I.e., Future.cancel(self). except Exception as exc: self.set_exception(exc) @@ -259,12 +259,19 @@ 'Task {!r} got Future {!r} attached to a ' 'different loop'.format(self, result))) elif blocking: - result._asyncio_future_blocking = False - result.add_done_callback(self._wakeup) - self._fut_waiter = result - if self._must_cancel: - if self._fut_waiter.cancel(): - self._must_cancel = False + if result is self: + self._loop.call_soon( + self._step, + RuntimeError( + 'Task cannot await on itself: {!r}'.format( + self))) + else: + result._asyncio_future_blocking = False + result.add_done_callback(self._wakeup) + self._fut_waiter = result + if self._must_cancel: + if self._fut_waiter.cancel(): + self._must_cancel = False else: self._loop.call_soon( self._step, diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -92,6 +92,17 @@ finally: other_loop.close() + def test_task_awaits_on_itself(self): + @asyncio.coroutine + def test(): + yield from task + + task = asyncio.ensure_future(test(), loop=self.loop) + + with self.assertRaisesRegex(RuntimeError, + 'Task cannot await on itself'): + self.loop.run_until_complete(task) + def test_task_class(self): @asyncio.coroutine def notmuch(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -228,6 +228,8 @@ - Issue #28399: Remove UNIX socket from FS before binding. Patch by ????????? ????. +- Issue #27972: Prohibit Tasks to await on themselves. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 12:21:24 2016 From: python-checkins at python.org (yury.selivanov) Date: Sun, 09 Oct 2016 16:21:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2327972=29?= Message-ID: <20161009162119.95017.87894.3ABF4DD0@psf.io> https://hg.python.org/cpython/rev/41c4f535b5c0 changeset: 104418:41c4f535b5c0 branch: 3.6 parent: 104415:019c5c2f1239 parent: 104417:8d877876aa89 user: Yury Selivanov date: Sun Oct 09 12:20:44 2016 -0400 summary: Merge 3.5 (issue #27972) files: Lib/asyncio/tasks.py | 21 +++++++++++----- Lib/test/test_asyncio/test_tasks.py | 11 ++++++++ Misc/NEWS | 2 + 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -241,7 +241,7 @@ result = coro.throw(exc) except StopIteration as exc: self.set_result(exc.value) - except futures.CancelledError as exc: + except futures.CancelledError: super().cancel() # I.e., Future.cancel(self). except Exception as exc: self.set_exception(exc) @@ -259,12 +259,19 @@ 'Task {!r} got Future {!r} attached to a ' 'different loop'.format(self, result))) elif blocking: - result._asyncio_future_blocking = False - result.add_done_callback(self._wakeup) - self._fut_waiter = result - if self._must_cancel: - if self._fut_waiter.cancel(): - self._must_cancel = False + if result is self: + self._loop.call_soon( + self._step, + RuntimeError( + 'Task cannot await on itself: {!r}'.format( + self))) + else: + result._asyncio_future_blocking = False + result.add_done_callback(self._wakeup) + self._fut_waiter = result + if self._must_cancel: + if self._fut_waiter.cancel(): + self._must_cancel = False else: self._loop.call_soon( self._step, diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -92,6 +92,17 @@ finally: other_loop.close() + def test_task_awaits_on_itself(self): + @asyncio.coroutine + def test(): + yield from task + + task = asyncio.ensure_future(test(), loop=self.loop) + + with self.assertRaisesRegex(RuntimeError, + 'Task cannot await on itself'): + self.loop.run_until_complete(task) + def test_task_class(self): @asyncio.coroutine def notmuch(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,8 @@ - Issue #28399: Remove UNIX socket from FS before binding. Patch by ????????? ????. +- Issue #27972: Prohibit Tasks to await on themselves. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 12:21:25 2016 From: python-checkins at python.org (yury.selivanov) Date: Sun, 09 Oct 2016 16:21:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3OTcy?= =?utf-8?q?=3A_Prohibit_Tasks_to_await_on_themselves=2E?= Message-ID: <20161009162118.75822.43186.E72B8E18@psf.io> https://hg.python.org/cpython/rev/8d877876aa89 changeset: 104417:8d877876aa89 branch: 3.5 parent: 104414:a3b162d5e70a user: Yury Selivanov date: Sun Oct 09 12:19:12 2016 -0400 summary: Issue #27972: Prohibit Tasks to await on themselves. files: Lib/asyncio/tasks.py | 21 +++++++++++----- Lib/test/test_asyncio/test_tasks.py | 11 ++++++++ Misc/NEWS | 2 + 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -241,7 +241,7 @@ result = coro.throw(exc) except StopIteration as exc: self.set_result(exc.value) - except futures.CancelledError as exc: + except futures.CancelledError: super().cancel() # I.e., Future.cancel(self). except Exception as exc: self.set_exception(exc) @@ -259,12 +259,19 @@ 'Task {!r} got Future {!r} attached to a ' 'different loop'.format(self, result))) elif blocking: - result._asyncio_future_blocking = False - result.add_done_callback(self._wakeup) - self._fut_waiter = result - if self._must_cancel: - if self._fut_waiter.cancel(): - self._must_cancel = False + if result is self: + self._loop.call_soon( + self._step, + RuntimeError( + 'Task cannot await on itself: {!r}'.format( + self))) + else: + result._asyncio_future_blocking = False + result.add_done_callback(self._wakeup) + self._fut_waiter = result + if self._must_cancel: + if self._fut_waiter.cancel(): + self._must_cancel = False else: self._loop.call_soon( self._step, diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -92,6 +92,17 @@ finally: other_loop.close() + def test_task_awaits_on_itself(self): + @asyncio.coroutine + def test(): + yield from task + + task = asyncio.ensure_future(test(), loop=self.loop) + + with self.assertRaisesRegex(RuntimeError, + 'Task cannot await on itself'): + self.loop.run_until_complete(task) + def test_task_class(self): @asyncio.coroutine def notmuch(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -388,6 +388,8 @@ - Issue #28399: Remove UNIX socket from FS before binding. Patch by ????????? ????. +- Issue #27972: Prohibit Tasks to await on themselves. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 13:05:04 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 17:05:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328339=3A_Remove_ByteString=2Eregister=28memoryv?= =?utf-8?b?aWV3KC4uLikpIGZyb20gdHlwaW5nLnB5Lg==?= Message-ID: <20161009170503.95234.34338.5BFFA5C7@psf.io> https://hg.python.org/cpython/rev/def461406c70 changeset: 104422:def461406c70 parent: 104419:47720192b318 parent: 104421:8958836a2c89 user: Guido van Rossum date: Sun Oct 09 10:04:55 2016 -0700 summary: Issue #28339: Remove ByteString.register(memoryview(...)) from typing.py. (merge 3.6->3.7) files: Lib/typing.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1668,9 +1668,6 @@ __slots__ = () -ByteString.register(type(memoryview(b''))) - - class List(list, MutableSequence[T], extra=list): __slots__ = () -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 13:05:04 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 17:05:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzM5?= =?utf-8?b?OiBSZW1vdmUgQnl0ZVN0cmluZy5yZWdpc3RlcihtZW1vcnl2aWV3KC4uLikp?= =?utf-8?q?_from_typing=2Epy=2E?= Message-ID: <20161009170503.95323.96073.980DF528@psf.io> https://hg.python.org/cpython/rev/69fe5f2e5aae changeset: 104420:69fe5f2e5aae branch: 3.5 parent: 104417:8d877876aa89 user: Guido van Rossum date: Sun Oct 09 10:02:49 2016 -0700 summary: Issue #28339: Remove ByteString.register(memoryview(...)) from typing.py. files: Lib/typing.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1668,9 +1668,6 @@ __slots__ = () -ByteString.register(type(memoryview(b''))) - - class List(list, MutableSequence[T], extra=list): __slots__ = () -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 13:05:04 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 09 Oct 2016 17:05:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328339=3A_Remove_ByteString=2Eregister=28memoryview=28?= =?utf-8?b?Li4uKSkgZnJvbSB0eXBpbmcucHku?= Message-ID: <20161009170503.17486.26243.C66DE11D@psf.io> https://hg.python.org/cpython/rev/8958836a2c89 changeset: 104421:8958836a2c89 branch: 3.6 parent: 104418:41c4f535b5c0 parent: 104420:69fe5f2e5aae user: Guido van Rossum date: Sun Oct 09 10:03:35 2016 -0700 summary: Issue #28339: Remove ByteString.register(memoryview(...)) from typing.py. (merge 3.5->3.6) files: Lib/typing.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1668,9 +1668,6 @@ __slots__ = () -ByteString.register(type(memoryview(b''))) - - class List(list, MutableSequence[T], extra=list): __slots__ = () -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 16:09:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 09 Oct 2016 20:09:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MTgz?= =?utf-8?q?=3A_Optimize_and_cleanup_dict_iteration=2E?= Message-ID: <20161009200921.75952.17476.9697F6CE@psf.io> https://hg.python.org/cpython/rev/112714f3745d changeset: 104423:112714f3745d branch: 3.6 parent: 104421:8958836a2c89 user: Serhiy Storchaka date: Sun Oct 09 23:08:05 2016 +0300 summary: Issue #28183: Optimize and cleanup dict iteration. files: Misc/NEWS | 2 + Objects/dictobject.c | 215 +++++++++++++++--------------- 2 files changed, 108 insertions(+), 109 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28183: Optimize and cleanup dict iteration. + - Issue #26081: Added C implementation of asyncio.Future. Original patch by Yury Selivanov. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1690,43 +1690,56 @@ assert(_PyDict_CheckConsistency(mp)); } -/* Returns -1 if no more items (or op is not a dict), - * index of item otherwise. Stores value in pvalue +/* Internal version of PyDict_Next that returns a hash value in addition + * to the key and value. + * Return 1 on success, return 0 when the reached the end of the dictionary + * (or if op is not a dictionary) */ -static inline Py_ssize_t -dict_next(PyObject *op, Py_ssize_t i, PyObject **pvalue) +int +_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, + PyObject **pvalue, Py_hash_t *phash) { - Py_ssize_t n; + Py_ssize_t i, n; PyDictObject *mp; - PyObject **value_ptr = NULL; + PyDictKeyEntry *entry_ptr; + PyObject *value; if (!PyDict_Check(op)) - return -1; + return 0; mp = (PyDictObject *)op; - if (i < 0) - return -1; - + i = *ppos; n = mp->ma_keys->dk_nentries; + if ((size_t)i >= (size_t)n) + return 0; if (mp->ma_values) { - for (; i < n; i++) { - value_ptr = &mp->ma_values[i]; - if (*value_ptr != NULL) - break; + PyObject **value_ptr = &mp->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; } + if (i >= n) + return 0; + entry_ptr = &DK_ENTRIES(mp->ma_keys)[i]; + value = *value_ptr; } else { - PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); - for (; i < n; i++) { - value_ptr = &ep0[i].me_value; - if (*value_ptr != NULL) - break; + entry_ptr = &DK_ENTRIES(mp->ma_keys)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; } + if (i >= n) + return 0; + value = entry_ptr->me_value; } - if (i >= n) - return -1; + *ppos = i+1; + if (pkey) + *pkey = entry_ptr->me_key; + if (phash) + *phash = entry_ptr->me_hash; if (pvalue) - *pvalue = *value_ptr; - return i; + *pvalue = value; + return 1; } /* @@ -1736,9 +1749,12 @@ * PyObject *key, *value; * i = 0; # important! i should not otherwise be changed by you * while (PyDict_Next(yourdict, &i, &key, &value)) { - * Refer to borrowed references in key and value. + * Refer to borrowed references in key and value. * } * + * Return 1 on success, return 0 when the reached the end of the dictionary + * (or if op is not a dictionary) + * * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that * mutates the dict. One exception: it is safe if the loop merely changes * the values associated with the keys (but doesn't insert new keys or @@ -1747,36 +1763,7 @@ int PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue) { - PyDictObject *mp = (PyDictObject*)op; - Py_ssize_t i = dict_next(op, *ppos, pvalue); - if (i < 0) - return 0; - mp = (PyDictObject *)op; - *ppos = i+1; - if (pkey) - *pkey = DK_ENTRIES(mp->ma_keys)[i].me_key; - return 1; -} - -/* Internal version of PyDict_Next that returns a hash value in addition - * to the key and value. - */ -int -_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, - PyObject **pvalue, Py_hash_t *phash) -{ - PyDictObject *mp; - PyDictKeyEntry *ep0; - Py_ssize_t i = dict_next(op, *ppos, pvalue); - if (i < 0) - return 0; - mp = (PyDictObject *)op; - ep0 = DK_ENTRIES(mp->ma_keys); - *ppos = i+1; - *phash = ep0[i].me_hash; - if (pkey) - *pkey = ep0[i].me_key; - return 1; + return _PyDict_Next(op, ppos, pkey, pvalue, NULL); } /* Internal version of dict.pop(). */ @@ -3352,13 +3339,13 @@ {NULL, NULL} /* sentinel */ }; -static PyObject *dictiter_iternextkey(dictiterobject *di) +static PyObject* +dictiter_iternextkey(dictiterobject *di) { PyObject *key; - Py_ssize_t i, n, offset; + Py_ssize_t i, n; PyDictKeysObject *k; PyDictObject *d = di->di_dict; - PyObject **value_ptr; if (d == NULL) return NULL; @@ -3372,27 +3359,30 @@ } i = di->di_pos; - if (i < 0) - goto fail; k = d->ma_keys; + n = k->dk_nentries; if (d->ma_values) { - value_ptr = &d->ma_values[i]; - offset = sizeof(PyObject *); + PyObject **value_ptr = &d->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; + } + if (i >= n) + goto fail; + key = DK_ENTRIES(k)[i].me_key; } else { - value_ptr = &DK_ENTRIES(k)[i].me_value; - offset = sizeof(PyDictKeyEntry); - } - n = k->dk_nentries - 1; - while (i <= n && *value_ptr == NULL) { - value_ptr = (PyObject **)(((char *)value_ptr) + offset); - i++; + PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; + } + if (i >= n) + goto fail; + key = entry_ptr->me_key; } di->di_pos = i+1; - if (i > n) - goto fail; di->len--; - key = DK_ENTRIES(k)[i].me_key; Py_INCREF(key); return key; @@ -3435,12 +3425,12 @@ 0, }; -static PyObject *dictiter_iternextvalue(dictiterobject *di) +static PyObject * +dictiter_iternextvalue(dictiterobject *di) { PyObject *value; - Py_ssize_t i, n, offset; + Py_ssize_t i, n; PyDictObject *d = di->di_dict; - PyObject **value_ptr; if (d == NULL) return NULL; @@ -3454,26 +3444,29 @@ } i = di->di_pos; - n = d->ma_keys->dk_nentries - 1; - if (i < 0 || i > n) - goto fail; + n = d->ma_keys->dk_nentries; if (d->ma_values) { - value_ptr = &d->ma_values[i]; - offset = sizeof(PyObject *); + PyObject **value_ptr = &d->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; + } + if (i >= n) + goto fail; + value = *value_ptr; } else { - value_ptr = &DK_ENTRIES(d->ma_keys)[i].me_value; - offset = sizeof(PyDictKeyEntry); - } - while (i <= n && *value_ptr == NULL) { - value_ptr = (PyObject **)(((char *)value_ptr) + offset); - i++; - if (i > n) + PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; + } + if (i >= n) goto fail; + value = entry_ptr->me_value; } di->di_pos = i+1; di->len--; - value = *value_ptr; Py_INCREF(value); return value; @@ -3504,7 +3497,7 @@ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)dictiter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -3516,12 +3509,12 @@ 0, }; -static PyObject *dictiter_iternextitem(dictiterobject *di) +static PyObject * +dictiter_iternextitem(dictiterobject *di) { PyObject *key, *value, *result = di->di_result; - Py_ssize_t i, n, offset; + Py_ssize_t i, n; PyDictObject *d = di->di_dict; - PyObject **value_ptr; if (d == NULL) return NULL; @@ -3535,37 +3528,41 @@ } i = di->di_pos; - if (i < 0) - goto fail; - n = d->ma_keys->dk_nentries - 1; + n = d->ma_keys->dk_nentries; if (d->ma_values) { - value_ptr = &d->ma_values[i]; - offset = sizeof(PyObject *); + PyObject **value_ptr = &d->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; + } + if (i >= n) + goto fail; + key = DK_ENTRIES(d->ma_keys)[i].me_key; + value = *value_ptr; } else { - value_ptr = &DK_ENTRIES(d->ma_keys)[i].me_value; - offset = sizeof(PyDictKeyEntry); - } - while (i <= n && *value_ptr == NULL) { - value_ptr = (PyObject **)(((char *)value_ptr) + offset); - i++; + PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; + } + if (i >= n) + goto fail; + key = entry_ptr->me_key; + value = entry_ptr->me_value; } di->di_pos = i+1; - if (i > n) - goto fail; - + di->len--; if (result->ob_refcnt == 1) { Py_INCREF(result); Py_DECREF(PyTuple_GET_ITEM(result, 0)); Py_DECREF(PyTuple_GET_ITEM(result, 1)); - } else { + } + else { result = PyTuple_New(2); if (result == NULL) return NULL; } - di->len--; - key = DK_ENTRIES(d->ma_keys)[i].me_key; - value = *value_ptr; Py_INCREF(key); Py_INCREF(value); PyTuple_SET_ITEM(result, 0, key); /* steals reference */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 16:09:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 09 Oct 2016 20:09:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjYu?= Message-ID: <20161009200921.82097.43357.8187A1C6@psf.io> https://hg.python.org/cpython/rev/c317075fcdd6 changeset: 104424:c317075fcdd6 parent: 104422:def461406c70 parent: 104423:112714f3745d user: Serhiy Storchaka date: Sun Oct 09 23:08:58 2016 +0300 summary: Merge from 3.6. files: Misc/NEWS | 2 + Objects/dictobject.c | 215 +++++++++++++++--------------- 2 files changed, 108 insertions(+), 109 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28183: Optimize and cleanup dict iteration. + - Issue #26081: Added C implementation of asyncio.Future. Original patch by Yury Selivanov. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1690,43 +1690,56 @@ assert(_PyDict_CheckConsistency(mp)); } -/* Returns -1 if no more items (or op is not a dict), - * index of item otherwise. Stores value in pvalue +/* Internal version of PyDict_Next that returns a hash value in addition + * to the key and value. + * Return 1 on success, return 0 when the reached the end of the dictionary + * (or if op is not a dictionary) */ -static inline Py_ssize_t -dict_next(PyObject *op, Py_ssize_t i, PyObject **pvalue) +int +_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, + PyObject **pvalue, Py_hash_t *phash) { - Py_ssize_t n; + Py_ssize_t i, n; PyDictObject *mp; - PyObject **value_ptr = NULL; + PyDictKeyEntry *entry_ptr; + PyObject *value; if (!PyDict_Check(op)) - return -1; + return 0; mp = (PyDictObject *)op; - if (i < 0) - return -1; - + i = *ppos; n = mp->ma_keys->dk_nentries; + if ((size_t)i >= (size_t)n) + return 0; if (mp->ma_values) { - for (; i < n; i++) { - value_ptr = &mp->ma_values[i]; - if (*value_ptr != NULL) - break; + PyObject **value_ptr = &mp->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; } + if (i >= n) + return 0; + entry_ptr = &DK_ENTRIES(mp->ma_keys)[i]; + value = *value_ptr; } else { - PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); - for (; i < n; i++) { - value_ptr = &ep0[i].me_value; - if (*value_ptr != NULL) - break; + entry_ptr = &DK_ENTRIES(mp->ma_keys)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; } + if (i >= n) + return 0; + value = entry_ptr->me_value; } - if (i >= n) - return -1; + *ppos = i+1; + if (pkey) + *pkey = entry_ptr->me_key; + if (phash) + *phash = entry_ptr->me_hash; if (pvalue) - *pvalue = *value_ptr; - return i; + *pvalue = value; + return 1; } /* @@ -1736,9 +1749,12 @@ * PyObject *key, *value; * i = 0; # important! i should not otherwise be changed by you * while (PyDict_Next(yourdict, &i, &key, &value)) { - * Refer to borrowed references in key and value. + * Refer to borrowed references in key and value. * } * + * Return 1 on success, return 0 when the reached the end of the dictionary + * (or if op is not a dictionary) + * * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that * mutates the dict. One exception: it is safe if the loop merely changes * the values associated with the keys (but doesn't insert new keys or @@ -1747,36 +1763,7 @@ int PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue) { - PyDictObject *mp = (PyDictObject*)op; - Py_ssize_t i = dict_next(op, *ppos, pvalue); - if (i < 0) - return 0; - mp = (PyDictObject *)op; - *ppos = i+1; - if (pkey) - *pkey = DK_ENTRIES(mp->ma_keys)[i].me_key; - return 1; -} - -/* Internal version of PyDict_Next that returns a hash value in addition - * to the key and value. - */ -int -_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, - PyObject **pvalue, Py_hash_t *phash) -{ - PyDictObject *mp; - PyDictKeyEntry *ep0; - Py_ssize_t i = dict_next(op, *ppos, pvalue); - if (i < 0) - return 0; - mp = (PyDictObject *)op; - ep0 = DK_ENTRIES(mp->ma_keys); - *ppos = i+1; - *phash = ep0[i].me_hash; - if (pkey) - *pkey = ep0[i].me_key; - return 1; + return _PyDict_Next(op, ppos, pkey, pvalue, NULL); } /* Internal version of dict.pop(). */ @@ -3352,13 +3339,13 @@ {NULL, NULL} /* sentinel */ }; -static PyObject *dictiter_iternextkey(dictiterobject *di) +static PyObject* +dictiter_iternextkey(dictiterobject *di) { PyObject *key; - Py_ssize_t i, n, offset; + Py_ssize_t i, n; PyDictKeysObject *k; PyDictObject *d = di->di_dict; - PyObject **value_ptr; if (d == NULL) return NULL; @@ -3372,27 +3359,30 @@ } i = di->di_pos; - if (i < 0) - goto fail; k = d->ma_keys; + n = k->dk_nentries; if (d->ma_values) { - value_ptr = &d->ma_values[i]; - offset = sizeof(PyObject *); + PyObject **value_ptr = &d->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; + } + if (i >= n) + goto fail; + key = DK_ENTRIES(k)[i].me_key; } else { - value_ptr = &DK_ENTRIES(k)[i].me_value; - offset = sizeof(PyDictKeyEntry); - } - n = k->dk_nentries - 1; - while (i <= n && *value_ptr == NULL) { - value_ptr = (PyObject **)(((char *)value_ptr) + offset); - i++; + PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; + } + if (i >= n) + goto fail; + key = entry_ptr->me_key; } di->di_pos = i+1; - if (i > n) - goto fail; di->len--; - key = DK_ENTRIES(k)[i].me_key; Py_INCREF(key); return key; @@ -3435,12 +3425,12 @@ 0, }; -static PyObject *dictiter_iternextvalue(dictiterobject *di) +static PyObject * +dictiter_iternextvalue(dictiterobject *di) { PyObject *value; - Py_ssize_t i, n, offset; + Py_ssize_t i, n; PyDictObject *d = di->di_dict; - PyObject **value_ptr; if (d == NULL) return NULL; @@ -3454,26 +3444,29 @@ } i = di->di_pos; - n = d->ma_keys->dk_nentries - 1; - if (i < 0 || i > n) - goto fail; + n = d->ma_keys->dk_nentries; if (d->ma_values) { - value_ptr = &d->ma_values[i]; - offset = sizeof(PyObject *); + PyObject **value_ptr = &d->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; + } + if (i >= n) + goto fail; + value = *value_ptr; } else { - value_ptr = &DK_ENTRIES(d->ma_keys)[i].me_value; - offset = sizeof(PyDictKeyEntry); - } - while (i <= n && *value_ptr == NULL) { - value_ptr = (PyObject **)(((char *)value_ptr) + offset); - i++; - if (i > n) + PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; + } + if (i >= n) goto fail; + value = entry_ptr->me_value; } di->di_pos = i+1; di->len--; - value = *value_ptr; Py_INCREF(value); return value; @@ -3504,7 +3497,7 @@ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)dictiter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -3516,12 +3509,12 @@ 0, }; -static PyObject *dictiter_iternextitem(dictiterobject *di) +static PyObject * +dictiter_iternextitem(dictiterobject *di) { PyObject *key, *value, *result = di->di_result; - Py_ssize_t i, n, offset; + Py_ssize_t i, n; PyDictObject *d = di->di_dict; - PyObject **value_ptr; if (d == NULL) return NULL; @@ -3535,37 +3528,41 @@ } i = di->di_pos; - if (i < 0) - goto fail; - n = d->ma_keys->dk_nentries - 1; + n = d->ma_keys->dk_nentries; if (d->ma_values) { - value_ptr = &d->ma_values[i]; - offset = sizeof(PyObject *); + PyObject **value_ptr = &d->ma_values[i]; + while (i < n && *value_ptr == NULL) { + value_ptr++; + i++; + } + if (i >= n) + goto fail; + key = DK_ENTRIES(d->ma_keys)[i].me_key; + value = *value_ptr; } else { - value_ptr = &DK_ENTRIES(d->ma_keys)[i].me_value; - offset = sizeof(PyDictKeyEntry); - } - while (i <= n && *value_ptr == NULL) { - value_ptr = (PyObject **)(((char *)value_ptr) + offset); - i++; + PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; + while (i < n && entry_ptr->me_value == NULL) { + entry_ptr++; + i++; + } + if (i >= n) + goto fail; + key = entry_ptr->me_key; + value = entry_ptr->me_value; } di->di_pos = i+1; - if (i > n) - goto fail; - + di->len--; if (result->ob_refcnt == 1) { Py_INCREF(result); Py_DECREF(PyTuple_GET_ITEM(result, 0)); Py_DECREF(PyTuple_GET_ITEM(result, 1)); - } else { + } + else { result = PyTuple_New(2); if (result == NULL) return NULL; } - di->len--; - key = DK_ENTRIES(d->ma_keys)[i].me_key; - value = *value_ptr; Py_INCREF(key); Py_INCREF(value); PyTuple_SET_ITEM(result, 0, key); /* steals reference */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 16:45:08 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 09 Oct 2016 20:45:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328400=3A_Removed_?= =?utf-8?q?uncessary_checks_in_unicode=5Fchar_and_resize=5Fcopy=2E?= Message-ID: <20161009204508.1333.68268.4EB3AD9D@psf.io> https://hg.python.org/cpython/rev/61e454a1c9d7 changeset: 104425:61e454a1c9d7 user: Serhiy Storchaka date: Sun Oct 09 23:44:48 2016 +0300 summary: Issue #28400: Removed uncessary checks in unicode_char and resize_copy. 1. In resize_copy we don't need to PyUnicode_READY(unicode) since when it's not PyUnicode_WCHAR_KIND it should be ready. 2. In unicode_char, PyUnicode_1BYTE_KIND is handled by get_latin1_char. Patch by Xiang Zhang. files: Objects/unicodeobject.c | 14 +++++--------- 1 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1029,8 +1029,7 @@ if (_PyUnicode_KIND(unicode) != PyUnicode_WCHAR_KIND) { PyObject *copy; - if (PyUnicode_READY(unicode) == -1) - return NULL; + assert(PyUnicode_IS_READY(unicode)); copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode)); if (copy == NULL) @@ -1974,14 +1973,11 @@ unicode = PyUnicode_New(1, ch); if (unicode == NULL) return NULL; - switch (PyUnicode_KIND(unicode)) { - case PyUnicode_1BYTE_KIND: - PyUnicode_1BYTE_DATA(unicode)[0] = (Py_UCS1)ch; - break; - case PyUnicode_2BYTE_KIND: + + assert(PyUnicode_KIND(unicode) != PyUnicode_1BYTE_KIND); + if (PyUnicode_KIND(unicode) == PyUnicode_2BYTE_KIND) { PyUnicode_2BYTE_DATA(unicode)[0] = (Py_UCS2)ch; - break; - default: + } else { assert(PyUnicode_KIND(unicode) == PyUnicode_4BYTE_KIND); PyUnicode_4BYTE_DATA(unicode)[0] = ch; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 21:34:46 2016 From: python-checkins at python.org (martin.panter) Date: Mon, 10 Oct 2016 01:34:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4Mzk0?= =?utf-8?q?=3A_More_typo_fixes_for_3=2E6+?= Message-ID: <20161010013446.1333.22214.7527F2C1@psf.io> https://hg.python.org/cpython/rev/004d1809db41 changeset: 104428:004d1809db41 branch: 3.6 user: Martin Panter date: Mon Oct 10 00:38:21 2016 +0000 summary: Issue #28394: More typo fixes for 3.6+ files: Doc/library/dis.rst | 2 +- Lib/test/test_ssl.py | 2 +- Modules/posixmodule.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -610,7 +610,7 @@ .. opcode:: SETUP_ANNOTATIONS Checks whether ``__annotations__`` is defined in ``locals()``, if not it is - set up to an empty ``dict``. This opcode is only emmitted if a class + set up to an empty ``dict``. This opcode is only emitted if a class or module body contains :term:`variable annotations ` statically. 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 @@ -3475,7 +3475,7 @@ client_context.verify_mode = ssl.CERT_REQUIRED client_context.load_verify_locations(SIGNING_CA) - # first conncetion without session + # first connection without session stats = server_params_test(client_context, server_context) session = stats['session'] self.assertTrue(session.id) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -770,7 +770,7 @@ * path.narrow * Points to the path if it was expressed as bytes, * or it was Unicode and was encoded to bytes. (On Windows, - * is an non-zero integer if the path was expressed as bytes. + * is a non-zero integer if the path was expressed as bytes. * The type is deliberately incompatible to prevent misuse.) * path.fd * Contains a file descriptor if path.accept_fd was true -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 21:34:46 2016 From: python-checkins at python.org (martin.panter) Date: Mon, 10 Oct 2016 01:34:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328394=3A_Merge_typo_fixes_from_3=2E5_into_3=2E6?= Message-ID: <20161010013446.20766.25559.64E37CD5@psf.io> https://hg.python.org/cpython/rev/bd113af10005 changeset: 104427:bd113af10005 branch: 3.6 parent: 104423:112714f3745d parent: 104426:6b1df8905012 user: Martin Panter date: Mon Oct 10 00:28:38 2016 +0000 summary: Issue #28394: Merge typo fixes from 3.5 into 3.6 files: Lib/lib2to3/Grammar.txt | 2 +- Lib/test/test_httplib.py | 2 +- Misc/HISTORY | 2 +- Misc/NEWS | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/lib2to3/Grammar.txt b/Lib/lib2to3/Grammar.txt --- a/Lib/lib2to3/Grammar.txt +++ b/Lib/lib2to3/Grammar.txt @@ -153,7 +153,7 @@ # to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, # we explicitly match '*' here, too, to give it proper precedence. # Illegal combinations and orderings are blocked in ast.c: -# multiple (test comp_for) arguements are blocked; keyword unpackings +# multiple (test comp_for) arguments are blocked; keyword unpackings # that precede iterable unpackings are blocked; etc. argument: ( test [comp_for] | test '=' test | diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1403,7 +1403,7 @@ def testHTTPSConnectionSourceAddress(self): self.conn = client.HTTPSConnection(HOST, self.port, source_address=('', self.source_port)) - # We don't test anything here other the constructor not barfing as + # We don't test anything here other than the constructor not barfing as # this code doesn't deal with setting up an active running SSL server # for an ssl_wrapped connect() to actually return from. diff --git a/Misc/HISTORY b/Misc/HISTORY --- a/Misc/HISTORY +++ b/Misc/HISTORY @@ -9016,7 +9016,7 @@ - Issue #5976: Fixed Distutils test_check_environ. - Issue #5941: Distutils build_clib command was not working anymore because - of an incomplete costumization of the archiver command. Added ARFLAGS in the + of an incomplete customization of the archiver command. Added ARFLAGS in the Makefile besides AR and make Distutils use it. Original patch by David Cournapeau. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -708,7 +708,7 @@ - Issue #21590: Support for DTrace and SystemTap probes. -- Issue #26307: The profile-opt build now applys PGO to the built-in modules. +- Issue #26307: The profile-opt build now applies PGO to the built-in modules. - Issue #26539: Add the --with-optimizations flag to turn on LTO and PGO build support when available. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 21:34:46 2016 From: python-checkins at python.org (martin.panter) Date: Mon, 10 Oct 2016 01:34:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzk0?= =?utf-8?q?=3A_Spelling_and_typo_fixes_in_code_comments_and_changelog?= Message-ID: <20161010013445.5035.51959.6318C4F0@psf.io> https://hg.python.org/cpython/rev/6b1df8905012 changeset: 104426:6b1df8905012 branch: 3.5 parent: 104420:69fe5f2e5aae user: Martin Panter date: Mon Oct 10 00:24:34 2016 +0000 summary: Issue #28394: Spelling and typo fixes in code comments and changelog Includes patch by Ville Skytt?. files: Lib/lib2to3/Grammar.txt | 2 +- Lib/test/test_httplib.py | 2 +- Misc/HISTORY | 2 +- Misc/NEWS | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/lib2to3/Grammar.txt b/Lib/lib2to3/Grammar.txt --- a/Lib/lib2to3/Grammar.txt +++ b/Lib/lib2to3/Grammar.txt @@ -152,7 +152,7 @@ # to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, # we explicitly match '*' here, too, to give it proper precedence. # Illegal combinations and orderings are blocked in ast.c: -# multiple (test comp_for) arguements are blocked; keyword unpackings +# multiple (test comp_for) arguments are blocked; keyword unpackings # that precede iterable unpackings are blocked; etc. argument: ( test [comp_for] | test '=' test | diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1272,7 +1272,7 @@ def testHTTPSConnectionSourceAddress(self): self.conn = client.HTTPSConnection(HOST, self.port, source_address=('', self.source_port)) - # We don't test anything here other the constructor not barfing as + # We don't test anything here other than the constructor not barfing as # this code doesn't deal with setting up an active running SSL server # for an ssl_wrapped connect() to actually return from. diff --git a/Misc/HISTORY b/Misc/HISTORY --- a/Misc/HISTORY +++ b/Misc/HISTORY @@ -9016,7 +9016,7 @@ - Issue #5976: Fixed Distutils test_check_environ. - Issue #5941: Distutils build_clib command was not working anymore because - of an incomplete costumization of the archiver command. Added ARFLAGS in the + of an incomplete customization of the archiver command. Added ARFLAGS in the Makefile besides AR and make Distutils use it. Original patch by David Cournapeau. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -484,7 +484,7 @@ make time when --with-optimizations is enabled. Also improve our ability to find the llvm-profdata tool on MacOS and some Linuxes. -- Issue #26307: The profile-opt build now applys PGO to the built-in modules. +- Issue #26307: The profile-opt build now applies PGO to the built-in modules. - Issue #26359: Add the --with-optimizations configure flag. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 21:34:46 2016 From: python-checkins at python.org (martin.panter) Date: Mon, 10 Oct 2016 01:34:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328394=3A_Merge_typo_fixes_from_3=2E6?= Message-ID: <20161010013446.5201.91117.5F284E07@psf.io> https://hg.python.org/cpython/rev/678fe178da0d changeset: 104429:678fe178da0d parent: 104425:61e454a1c9d7 parent: 104428:004d1809db41 user: Martin Panter date: Mon Oct 10 00:42:50 2016 +0000 summary: Issue #28394: Merge typo fixes from 3.6 files: Doc/library/dis.rst | 2 +- Lib/lib2to3/Grammar.txt | 2 +- Lib/test/test_httplib.py | 2 +- Lib/test/test_ssl.py | 2 +- Misc/HISTORY | 2 +- Misc/NEWS | 2 +- Modules/posixmodule.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -610,7 +610,7 @@ .. opcode:: SETUP_ANNOTATIONS Checks whether ``__annotations__`` is defined in ``locals()``, if not it is - set up to an empty ``dict``. This opcode is only emmitted if a class + set up to an empty ``dict``. This opcode is only emitted if a class or module body contains :term:`variable annotations ` statically. diff --git a/Lib/lib2to3/Grammar.txt b/Lib/lib2to3/Grammar.txt --- a/Lib/lib2to3/Grammar.txt +++ b/Lib/lib2to3/Grammar.txt @@ -153,7 +153,7 @@ # to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, # we explicitly match '*' here, too, to give it proper precedence. # Illegal combinations and orderings are blocked in ast.c: -# multiple (test comp_for) arguements are blocked; keyword unpackings +# multiple (test comp_for) arguments are blocked; keyword unpackings # that precede iterable unpackings are blocked; etc. argument: ( test [comp_for] | test '=' test | diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1403,7 +1403,7 @@ def testHTTPSConnectionSourceAddress(self): self.conn = client.HTTPSConnection(HOST, self.port, source_address=('', self.source_port)) - # We don't test anything here other the constructor not barfing as + # We don't test anything here other than the constructor not barfing as # this code doesn't deal with setting up an active running SSL server # for an ssl_wrapped connect() to actually return from. 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 @@ -3475,7 +3475,7 @@ client_context.verify_mode = ssl.CERT_REQUIRED client_context.load_verify_locations(SIGNING_CA) - # first conncetion without session + # first connection without session stats = server_params_test(client_context, server_context) session = stats['session'] self.assertTrue(session.id) diff --git a/Misc/HISTORY b/Misc/HISTORY --- a/Misc/HISTORY +++ b/Misc/HISTORY @@ -13317,7 +13317,7 @@ - Issue #5976: Fixed Distutils test_check_environ. - Issue #5941: Distutils build_clib command was not working anymore because - of an incomplete costumization of the archiver command. Added ARFLAGS in the + of an incomplete customization of the archiver command. Added ARFLAGS in the Makefile besides AR and make Distutils use it. Original patch by David Cournapeau. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -743,7 +743,7 @@ - Issue #21590: Support for DTrace and SystemTap probes. -- Issue #26307: The profile-opt build now applys PGO to the built-in modules. +- Issue #26307: The profile-opt build now applies PGO to the built-in modules. - Issue #26539: Add the --with-optimizations flag to turn on LTO and PGO build support when available. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -770,7 +770,7 @@ * path.narrow * Points to the path if it was expressed as bytes, * or it was Unicode and was encoded to bytes. (On Windows, - * is an non-zero integer if the path was expressed as bytes. + * is a non-zero integer if the path was expressed as bytes. * The type is deliberately incompatible to prevent misuse.) * path.fd * Contains a file descriptor if path.accept_fd was true -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 21:34:46 2016 From: python-checkins at python.org (martin.panter) Date: Mon, 10 Oct 2016 01:34:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4Mzk0?= =?utf-8?q?=3A_Typo_fixes_in_code_comments_and_changelog?= Message-ID: <20161010013446.5183.19971.F75190FD@psf.io> https://hg.python.org/cpython/rev/de13f5a0f4d5 changeset: 104430:de13f5a0f4d5 branch: 2.7 parent: 104366:3119f08802a5 user: Martin Panter date: Mon Oct 10 01:00:00 2016 +0000 summary: Issue #28394: Typo fixes in code comments and changelog Includes patch by Ville Skytt?. files: Lib/lib2to3/Grammar.txt | 2 +- Lib/test/test_httplib.py | 2 +- Misc/NEWS | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/lib2to3/Grammar.txt b/Lib/lib2to3/Grammar.txt --- a/Lib/lib2to3/Grammar.txt +++ b/Lib/lib2to3/Grammar.txt @@ -150,7 +150,7 @@ # to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, # we explicitly match '*' here, too, to give it proper precedence. # Illegal combinations and orderings are blocked in ast.c: -# multiple (test comp_for) arguements are blocked; keyword unpackings +# multiple (test comp_for) arguments are blocked; keyword unpackings # that precede iterable unpackings are blocked; etc. argument: ( test [comp_for] | test '=' test | diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -738,7 +738,7 @@ def testHTTPSConnectionSourceAddress(self): self.conn = httplib.HTTPSConnection(HOST, self.port, source_address=('', self.source_port)) - # We don't test anything here other the constructor not barfing as + # We don't test anything here other than the constructor not barfing as # this code doesn't deal with setting up an active running SSL server # for an ssl_wrapped connect() to actually return from. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,7 +25,7 @@ - Issue #15578: Correctly incref the parent module while importing. -- Issue #26307: The profile-opt build now applys PGO to the built-in modules. +- Issue #26307: The profile-opt build now applies PGO to the built-in modules. - Issue #26020: set literal evaluation order did not match documented behaviour. @@ -488,7 +488,7 @@ - Issue #26385: Remove the file if the internal fdopen() call in NamedTemporaryFile() fails. Based on patch by Silent Ghost. -- Issue #26309: In the "socketserver" module, shut down the request (closing +- Issue #26309: In the "SocketServer" module, shut down the request (closing the connected socket) when verify_request() returns false. Based on patch by Aviv Palivoda. @@ -6537,7 +6537,7 @@ - Issue #8140: Extend compileall to compile single files. Add -i option. - Issue #7774: Set sys.executable to an empty string if ``argv[0]`` has been set - to an non existent program name and Python is unable to retrieve the real + to a non existent program name and Python is unable to retrieve the real program name. - Issue #8117: logging: Improved algorithm for computing initial rollover time @@ -8053,7 +8053,7 @@ is used. Original patch by Floris Bruynooghe. - Issue #5941: Distutils build_clib command was not working anymore because of - an incomplete costumization of the archiver command. Added ARFLAGS in the + an incomplete customization of the archiver command. Added ARFLAGS in the Makefile besides AR and make Distutils use it. Original patch by David Cournapeau. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 23:19:41 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 10 Oct 2016 03:19:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDAy?= =?utf-8?q?=3A_Adds_signed_catalog_files_for_stdlib_on_Windows=2E?= Message-ID: <20161010031940.79450.32229.DE97AB07@psf.io> https://hg.python.org/cpython/rev/e050ed5da06d changeset: 104431:e050ed5da06d branch: 3.6 parent: 104428:004d1809db41 user: Steve Dower date: Sun Oct 09 20:18:52 2016 -0700 summary: Issue #28402: Adds signed catalog files for stdlib on Windows. files: Misc/NEWS | 2 + PCbuild/pyproject.props | 12 ++++--- Tools/msi/common.wxs | 4 +- Tools/msi/lib/lib.wixproj | 1 + Tools/msi/lib/lib.wxs | 1 + Tools/msi/lib/lib_files.wxs | 7 ++++ Tools/msi/msi.props | 2 + Tools/msi/msi.targets | 33 ++++++++++++++++++++- Tools/msi/tools/tools.wixproj | 1 + Tools/msi/tools/tools.wxs | 1 + Tools/msi/tools/tools_files.wxs | 7 ++++ 11 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -226,6 +226,8 @@ Windows ------- +- Issue #28402: Adds signed catalog files for stdlib on Windows. + - Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by Eryk Sun) diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -147,11 +147,13 @@ Targets="CleanAll" /> - - $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot81)\bin\x86\signtool.exe - $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot)\bin\x86\signtool.exe - $(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A at InstallationFolder)\Bin\signtool.exe - <_SignCommand Condition="Exists($(SignToolPath))">"$(SignToolPath)" sign /q /n "$(SigningCertificate)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" + + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot10)\bin\x86 + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot81)\bin\x86 + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot)\bin\x86 + $(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A at InstallationFolder)\Bin\ + <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificate)' != '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /q /n "$(SigningCertificate)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" + <_MakeCatCommand Condition="Exists($(SdkBinPath))">"$(SdkBinPath)\makecat.exe" diff --git a/Tools/msi/common.wxs b/Tools/msi/common.wxs --- a/Tools/msi/common.wxs +++ b/Tools/msi/common.wxs @@ -63,7 +63,9 @@ - + + + diff --git a/Tools/msi/lib/lib.wixproj b/Tools/msi/lib/lib.wixproj --- a/Tools/msi/lib/lib.wixproj +++ b/Tools/msi/lib/lib.wixproj @@ -27,6 +27,7 @@ $(PySourcePath)Lib Lib\ lib_py + true diff --git a/Tools/msi/lib/lib.wxs b/Tools/msi/lib/lib.wxs --- a/Tools/msi/lib/lib.wxs +++ b/Tools/msi/lib/lib.wxs @@ -11,6 +11,7 @@ + diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -70,4 +70,11 @@ + + + + + + + diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -11,6 +11,7 @@ Release x86 perUser + <_MakeCatCommand Condition="'$(_MakeCatCommand)' == ''">makecat @@ -103,6 +104,7 @@ generated_filelist + false false diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -12,8 +12,10 @@ <_Source>%(Source)$([msbuild]::MakeRelative(%(SourceBase), %(FullPath))) <_Target>%(Target_)$([msbuild]::MakeRelative(%(TargetBase), %(FullPath))) + + <_CatalogFiles Include="@(InstallFiles)" Condition="%(InstallFiles.IncludeInCat) and ''!=$([System.IO.File]::ReadAllText(%(InstallFiles.FullPath)))" /> - + @@ -24,6 +26,35 @@ + + + <_CatFileSourceTarget>$(IntermediateOutputPath)$(MSBuildProjectName).cdf + <_CatFileTarget>$(IntermediateOutputPath)python_$(MSBuildProjectName).cat + <_CatFile>[CatalogHeader] +Name=$([System.IO.Path]::GetFileName($(_CatFileTarget))) +ResultDir=$([System.IO.Path]::GetDirectoryName($(_CatFileTarget))) +PublicVersion=1 +CatalogVersion=2 +HashAlgorithms=SHA256 +PageHashes=false +EncodingType= + +[CatalogFiles] +@(_CatalogFiles->'<HASH>%(Filename)%(Extension)=%(FullPath)',' +') + + + + + + + + + + + + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)$(PyTestExt)`).Replace(`{{LongVersion}}`, `$(PythonVersion)$(PyTestExt)`).Replace(`{{Bitness}}`, `$(Bitness)`)) diff --git a/Tools/msi/tools/tools.wixproj b/Tools/msi/tools/tools.wixproj --- a/Tools/msi/tools/tools.wixproj +++ b/Tools/msi/tools/tools.wixproj @@ -36,6 +36,7 @@ $(PySourcePath) tools_py + true diff --git a/Tools/msi/tools/tools.wxs b/Tools/msi/tools/tools.wxs --- a/Tools/msi/tools/tools.wxs +++ b/Tools/msi/tools/tools.wxs @@ -9,6 +9,7 @@ + diff --git a/Tools/msi/tools/tools_files.wxs b/Tools/msi/tools/tools_files.wxs --- a/Tools/msi/tools/tools_files.wxs +++ b/Tools/msi/tools/tools_files.wxs @@ -13,4 +13,11 @@ + + + + + + + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 9 23:19:41 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 10 Oct 2016 03:19:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328402=3A_Adds_signed_catalog_files_for_stdlib_o?= =?utf-8?q?n_Windows=2E?= Message-ID: <20161010031941.75771.62822.03315D58@psf.io> https://hg.python.org/cpython/rev/27edae50e62c changeset: 104432:27edae50e62c parent: 104429:678fe178da0d parent: 104431:e050ed5da06d user: Steve Dower date: Sun Oct 09 20:19:21 2016 -0700 summary: Issue #28402: Adds signed catalog files for stdlib on Windows. files: Misc/NEWS | 2 + PCbuild/pyproject.props | 12 ++++--- Tools/msi/common.wxs | 4 +- Tools/msi/lib/lib.wixproj | 1 + Tools/msi/lib/lib.wxs | 1 + Tools/msi/lib/lib_files.wxs | 7 ++++ Tools/msi/msi.props | 2 + Tools/msi/msi.targets | 33 ++++++++++++++++++++- Tools/msi/tools/tools.wixproj | 1 + Tools/msi/tools/tools.wxs | 1 + Tools/msi/tools/tools_files.wxs | 7 ++++ 11 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -235,6 +235,8 @@ Windows ------- +- Issue #28402: Adds signed catalog files for stdlib on Windows. + - Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by Eryk Sun) diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -147,11 +147,13 @@ Targets="CleanAll" /> - - $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot81)\bin\x86\signtool.exe - $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot)\bin\x86\signtool.exe - $(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A at InstallationFolder)\Bin\signtool.exe - <_SignCommand Condition="Exists($(SignToolPath))">"$(SignToolPath)" sign /q /n "$(SigningCertificate)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" + + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot10)\bin\x86 + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot81)\bin\x86 + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot)\bin\x86 + $(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A at InstallationFolder)\Bin\ + <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificate)' != '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /q /n "$(SigningCertificate)" /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" + <_MakeCatCommand Condition="Exists($(SdkBinPath))">"$(SdkBinPath)\makecat.exe" diff --git a/Tools/msi/common.wxs b/Tools/msi/common.wxs --- a/Tools/msi/common.wxs +++ b/Tools/msi/common.wxs @@ -63,7 +63,9 @@ - + + + diff --git a/Tools/msi/lib/lib.wixproj b/Tools/msi/lib/lib.wixproj --- a/Tools/msi/lib/lib.wixproj +++ b/Tools/msi/lib/lib.wixproj @@ -27,6 +27,7 @@ $(PySourcePath)Lib Lib\ lib_py + true diff --git a/Tools/msi/lib/lib.wxs b/Tools/msi/lib/lib.wxs --- a/Tools/msi/lib/lib.wxs +++ b/Tools/msi/lib/lib.wxs @@ -11,6 +11,7 @@ + diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -70,4 +70,11 @@ + + + + + + + diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -11,6 +11,7 @@ Release x86 perUser + <_MakeCatCommand Condition="'$(_MakeCatCommand)' == ''">makecat @@ -103,6 +104,7 @@ generated_filelist + false false diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets --- a/Tools/msi/msi.targets +++ b/Tools/msi/msi.targets @@ -12,8 +12,10 @@ <_Source>%(Source)$([msbuild]::MakeRelative(%(SourceBase), %(FullPath))) <_Target>%(Target_)$([msbuild]::MakeRelative(%(TargetBase), %(FullPath))) + + <_CatalogFiles Include="@(InstallFiles)" Condition="%(InstallFiles.IncludeInCat) and ''!=$([System.IO.File]::ReadAllText(%(InstallFiles.FullPath)))" /> - + @@ -24,6 +26,35 @@ + + + <_CatFileSourceTarget>$(IntermediateOutputPath)$(MSBuildProjectName).cdf + <_CatFileTarget>$(IntermediateOutputPath)python_$(MSBuildProjectName).cat + <_CatFile>[CatalogHeader] +Name=$([System.IO.Path]::GetFileName($(_CatFileTarget))) +ResultDir=$([System.IO.Path]::GetDirectoryName($(_CatFileTarget))) +PublicVersion=1 +CatalogVersion=2 +HashAlgorithms=SHA256 +PageHashes=false +EncodingType= + +[CatalogFiles] +@(_CatalogFiles->'<HASH>%(Filename)%(Extension)=%(FullPath)',' +') + + + + + + + + + + + + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)$(PyTestExt)`).Replace(`{{LongVersion}}`, `$(PythonVersion)$(PyTestExt)`).Replace(`{{Bitness}}`, `$(Bitness)`)) diff --git a/Tools/msi/tools/tools.wixproj b/Tools/msi/tools/tools.wixproj --- a/Tools/msi/tools/tools.wixproj +++ b/Tools/msi/tools/tools.wixproj @@ -36,6 +36,7 @@ $(PySourcePath) tools_py + true diff --git a/Tools/msi/tools/tools.wxs b/Tools/msi/tools/tools.wxs --- a/Tools/msi/tools/tools.wxs +++ b/Tools/msi/tools/tools.wxs @@ -9,6 +9,7 @@ + diff --git a/Tools/msi/tools/tools_files.wxs b/Tools/msi/tools/tools_files.wxs --- a/Tools/msi/tools/tools_files.wxs +++ b/Tools/msi/tools/tools_files.wxs @@ -13,4 +13,11 @@ + + + + + + + -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Mon Oct 10 12:21:29 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 10 Oct 2016 17:21:29 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-10 Message-ID: <3b70a59f-1dd2-4701-a432-2f21c5b87c2a@irsmsx101.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-10 02:47:18 +0000 commit: de13f5a0f4d5 previous commit: 59260b38f7cd revision date: 2016-10-10 01:00:00 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% 0.58% 5.15% 4.75% :-) pybench 0.26% -0.17% 5.93% 4.34% :-( regex_v8 0.69% 0.08% -2.24% 11.29% :-) nbody 0.07% 0.52% 7.99% 3.48% :-) json_dump_v2 0.28% -0.05% 2.89% 9.56% :-| normal_startup 1.07% -0.53% -0.22% 2.35% :-) ssbench 0.28% 0.02% 2.06% 1.45% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-10/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Mon Oct 10 12:22:46 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 10 Oct 2016 17:22:46 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-10 Message-ID: Results for project Python default, build date 2016-10-10 02:01:08 +0000 commit: 678fe178da0d previous commit: fca5c4a63251 revision date: 2016-10-10 00:42:50 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.20% 0.21% 5.82% 14.71% :-) pybench 0.17% 0.17% 5.46% 5.05% :-( regex_v8 3.69% -1.51% -3.34% 4.00% :-) nbody 0.09% -0.24% 3.53% 4.51% :-( json_dump_v2 0.39% 1.58% -11.97% 15.56% :-| normal_startup 1.04% 0.65% 1.94% 5.55% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-10/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Mon Oct 10 13:13:03 2016 From: python-checkins at python.org (inada.naoki) Date: Mon, 10 Oct 2016 17:13:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328405=3A_Fix_compile_error_for_=5Ffuturesmodule?= =?utf-8?q?=2Ec_on_Cygwin=2E?= Message-ID: <20161010171301.1447.73269.7A4D8DA0@psf.io> https://hg.python.org/cpython/rev/d2a313d13542 changeset: 104434:d2a313d13542 parent: 104432:27edae50e62c parent: 104433:a8dd18e375c8 user: INADA Naoki date: Tue Oct 11 02:12:52 2016 +0900 summary: Issue #28405: Fix compile error for _futuresmodule.c on Cygwin. Patch by Masayuki Yamamoto. files: Modules/_futuresmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c --- a/Modules/_futuresmodule.c +++ b/Modules/_futuresmodule.c @@ -943,7 +943,7 @@ } Py_INCREF(fut); it->future = (FutureObj*)fut; - _PyObject_GC_TRACK(it); + PyObject_GC_Track(it); return (PyObject*)it; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 13:13:03 2016 From: python-checkins at python.org (inada.naoki) Date: Mon, 10 Oct 2016 17:13:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDA1?= =?utf-8?q?=3A_Fix_compile_error_for_=5Ffuturesmodule=2Ec_on_Cygwin=2E?= Message-ID: <20161010171301.20873.5182.E5F8BEF8@psf.io> https://hg.python.org/cpython/rev/a8dd18e375c8 changeset: 104433:a8dd18e375c8 branch: 3.6 parent: 104431:e050ed5da06d user: INADA Naoki date: Tue Oct 11 02:12:34 2016 +0900 summary: Issue #28405: Fix compile error for _futuresmodule.c on Cygwin. Patch by Masayuki Yamamoto. files: Modules/_futuresmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c --- a/Modules/_futuresmodule.c +++ b/Modules/_futuresmodule.c @@ -943,7 +943,7 @@ } Py_INCREF(fut); it->future = (FutureObj*)fut; - _PyObject_GC_TRACK(it); + PyObject_GC_Track(it); return (PyObject*)it; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 15:35:13 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 10 Oct 2016 19:35:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E6?= Message-ID: <20161010193512.21280.65138.DCBFDFDA@psf.io> https://hg.python.org/cpython/rev/aeb46d723483 changeset: 104436:aeb46d723483 parent: 104434:d2a313d13542 parent: 104435:d05bffc06b2d user: Ned Deily date: Mon Oct 10 15:34:47 2016 -0400 summary: merge with 3.6 files: Mac/BuildScript/resources/ReadMe.rtf | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1504 +{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf390 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;\csgray\c100000;} @@ -43,7 +43,7 @@ \f1 certifi \f0 package ({\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/certifi"}}{\fldrslt https://pypi.python.org/pypi/certifi}}). If you choose to use \f1 certifi -\f0 , you should consider subscribing to the{\field{\*\fldinst{HYPERLINK "https://certifi.io/en/latest/"}}{\fldrslt project's email update service}} to be notified when the certificate bundle is updated.\ +\f0 , you should consider subscribing to the{\field{\*\fldinst{HYPERLINK "https://certifi.io/en/latest/"}}{\fldrslt project's email update service}} to be notified when the certificate bundle is updated. More options will be provided prior to the final release of 3.6.0.\ \ The bundled \f1 pip @@ -58,7 +58,7 @@ \i Tcl/Tk \i0 frameworks. Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information about supported and recommended versions of \i Tcl/Tk -\i0 for this version of Python and of Mac OS X. For the initial alpha releases of Python 3.6, the installer is still linked with Tcl/Tk 8.5; this will change prior to the beta 2 release of 3.6.0.\ +\i0 for this version of Python and of Mac OS X. For the initial preview releases of Python 3.6, the installer is still linked with Tcl/Tk 8.5; this will likely change prior to the final release of 3.6.0.\ \b \ul \ Other changes\ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 15:35:13 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 10 Oct 2016 19:35:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Update_OS_X_in?= =?utf-8?q?staller_ReadMe_for_360b2=2E?= Message-ID: <20161010193512.79404.31205.C1A431FF@psf.io> https://hg.python.org/cpython/rev/d05bffc06b2d changeset: 104435:d05bffc06b2d branch: 3.6 parent: 104433:a8dd18e375c8 user: Ned Deily date: Mon Oct 10 15:34:00 2016 -0400 summary: Update OS X installer ReadMe for 360b2. files: Mac/BuildScript/resources/ReadMe.rtf | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1504 +{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf390 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;\csgray\c100000;} @@ -43,7 +43,7 @@ \f1 certifi \f0 package ({\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/certifi"}}{\fldrslt https://pypi.python.org/pypi/certifi}}). If you choose to use \f1 certifi -\f0 , you should consider subscribing to the{\field{\*\fldinst{HYPERLINK "https://certifi.io/en/latest/"}}{\fldrslt project's email update service}} to be notified when the certificate bundle is updated.\ +\f0 , you should consider subscribing to the{\field{\*\fldinst{HYPERLINK "https://certifi.io/en/latest/"}}{\fldrslt project's email update service}} to be notified when the certificate bundle is updated. More options will be provided prior to the final release of 3.6.0.\ \ The bundled \f1 pip @@ -58,7 +58,7 @@ \i Tcl/Tk \i0 frameworks. Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information about supported and recommended versions of \i Tcl/Tk -\i0 for this version of Python and of Mac OS X. For the initial alpha releases of Python 3.6, the installer is still linked with Tcl/Tk 8.5; this will change prior to the beta 2 release of 3.6.0.\ +\i0 for this version of Python and of Mac OS X. For the initial preview releases of Python 3.6, the installer is still linked with Tcl/Tk 8.5; this will likely change prior to the final release of 3.6.0.\ \b \ul \ Other changes\ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 15:45:37 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 10 Oct 2016 19:45:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_null_merge?= Message-ID: <20161010194537.15207.34932.2F49456E@psf.io> https://hg.python.org/cpython/rev/22d65e92a156 changeset: 104438:22d65e92a156 parent: 104436:aeb46d723483 parent: 104437:17bd5239b886 user: Ned Deily date: Mon Oct 10 15:45:04 2016 -0400 summary: null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 15:45:37 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 10 Oct 2016 19:45:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_regenerate_con?= =?utf-8?q?figure_with_autoconf_2=2E69?= Message-ID: <20161010194537.5074.29096.504D9AFD@psf.io> https://hg.python.org/cpython/rev/17bd5239b886 changeset: 104437:17bd5239b886 branch: 3.6 parent: 104435:d05bffc06b2d user: Ned Deily date: Mon Oct 10 15:42:18 2016 -0400 summary: regenerate configure with autoconf 2.69 files: configure | 14 +------------- 1 files changed, 1 insertions(+), 13 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -784,7 +784,6 @@ docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -895,7 +894,6 @@ sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1148,15 +1146,6 @@ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1294,7 +1283,7 @@ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1447,7 +1436,6 @@ --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 19:19:34 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 10 Oct 2016 23:19:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Fix_launcher?= =?utf-8?q?=2Emsi_from_rebuilding_during_release_build=2E?= Message-ID: <20161010231933.20698.64350.7D53847F@psf.io> https://hg.python.org/cpython/rev/f7bf01d91abf changeset: 104439:f7bf01d91abf branch: 3.6 parent: 104437:17bd5239b886 user: Steve Dower date: Mon Oct 10 16:19:06 2016 -0700 summary: Fix launcher.msi from rebuilding during release build. files: Tools/msi/buildrelease.bat | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -170,8 +170,15 @@ @echo off ) +if "%OUTDIR_PLAT%" EQU "win32" ( + msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI% + if errorlevel 1 exit /B +) else if not exist "%PCBUILD%win32\en-us\launcher.msi" ( + msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI% + if errorlevel 1 exit /B +) + set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI% -msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI% msbuild "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true if errorlevel 1 exit /B msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 19:19:34 2016 From: python-checkins at python.org (steve.dower) Date: Mon, 10 Oct 2016 23:19:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Fix_launcher=2Emsi_from_rebuilding_during_release_build?= =?utf-8?q?=2E?= Message-ID: <20161010231933.82235.29540.C5B5D5AD@psf.io> https://hg.python.org/cpython/rev/c1960fbb2d96 changeset: 104440:c1960fbb2d96 parent: 104438:22d65e92a156 parent: 104439:f7bf01d91abf user: Steve Dower date: Mon Oct 10 16:19:20 2016 -0700 summary: Fix launcher.msi from rebuilding during release build. files: Tools/msi/buildrelease.bat | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -168,8 +168,15 @@ @echo off ) +if "%OUTDIR_PLAT%" EQU "win32" ( + msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI% + if errorlevel 1 exit /B +) else if not exist "%PCBUILD%win32\en-us\launcher.msi" ( + msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI% + if errorlevel 1 exit /B +) + set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI% -msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI% msbuild "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true if errorlevel 1 exit /B msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 20:58:42 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 11 Oct 2016 00:58:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Update_pydoc_t?= =?utf-8?q?opics_for_3=2E6=2E0b2?= Message-ID: <20161011005841.15249.75793.28975E9B@psf.io> https://hg.python.org/cpython/rev/91639574f2ed changeset: 104441:91639574f2ed branch: 3.6 parent: 104437:17bd5239b886 user: Ned Deily date: Mon Oct 10 16:02:26 2016 -0400 summary: Update pydoc topics for 3.6.0b2 files: Lib/pydoc_data/topics.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Sep 12 10:47:11 2016 +# Autogenerated by Sphinx on Mon Oct 10 15:59:17 2016 topics = {'assert': '\n' 'The "assert" statement\n' '**********************\n' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 20:58:42 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 11 Oct 2016 00:58:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Version_bump_f?= =?utf-8?q?or_3=2E6=2E0b2?= Message-ID: <20161011005842.85635.3190.6DC87E6E@psf.io> https://hg.python.org/cpython/rev/b9fadc7d1c3f changeset: 104442:b9fadc7d1c3f branch: 3.6 tag: v3.6.0b2 user: Ned Deily date: Mon Oct 10 16:09:08 2016 -0400 summary: Version bump for 3.6.0b2 files: Include/patchlevel.h | 4 ++-- Misc/NEWS | 4 +++- README | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 6 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.6.0b1+" +#define PY_VERSION "3.6.0b2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 3.6.0 beta 2 ================================= -*Release date: XXXX-XX-XX* +*Release date: 2016-10-10* Core and Builtins ----------------- @@ -266,6 +266,7 @@ - Issue #28217: Adds _testconsole module to test console input. + What's New in Python 3.6.0 beta 1 ================================= @@ -1001,6 +1002,7 @@ - Issue #10910: Avoid C++ compilation errors on FreeBSD and OS X. Also update FreedBSD version checks for the original ctype UTF-8 workaround. + What's New in Python 3.6.0 alpha 3 ================================== diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.6.0 beta 1 +This is Python version 3.6.0 beta 2 =================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 20:58:42 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 11 Oct 2016 00:58:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Added_tag_v3?= =?utf-8?q?=2E6=2E0b2_for_changeset_b9fadc7d1c3f?= Message-ID: <20161011005842.20329.30501.1838C108@psf.io> https://hg.python.org/cpython/rev/459049fb48ae changeset: 104443:459049fb48ae branch: 3.6 user: Ned Deily date: Mon Oct 10 16:09:41 2016 -0400 summary: Added tag v3.6.0b2 for changeset b9fadc7d1c3f files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -171,3 +171,4 @@ f3edf13dc339b8942ae6b309771ab197dd8ce6fa v3.6.0a3 017cf260936b444788c9b671d195b7bfd83dbd25 v3.6.0a4 5b0ca4ed5e2f0669d76ece7ef975c544580f12b4 v3.6.0b1 +b9fadc7d1c3f9c3c77f32f35afbe1a1cc38070e6 v3.6.0b2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 20:58:42 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 11 Oct 2016 00:58:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogU3RhcnQgMy42LjBi?= =?utf-8?q?3?= Message-ID: <20161011005842.17441.45117.6AAFC34F@psf.io> https://hg.python.org/cpython/rev/32598eb8861a changeset: 104444:32598eb8861a branch: 3.6 user: Ned Deily date: Mon Oct 10 20:46:40 2016 -0400 summary: Start 3.6.0b3 files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.6.0b2" +#define PY_VERSION "3.6.0b2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.6.0 beta 3 +================================= + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.6.0 beta 2 ================================= -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 20:58:42 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 11 Oct 2016 00:58:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy42IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E6_releasing_branch?= Message-ID: <20161011005842.79555.61784.D0E2DBEE@psf.io> https://hg.python.org/cpython/rev/cd5f20f75857 changeset: 104445:cd5f20f75857 branch: 3.6 parent: 104439:f7bf01d91abf parent: 104444:32598eb8861a user: Ned Deily date: Mon Oct 10 20:53:33 2016 -0400 summary: Merge 3.6 releasing branch files: .hgtags | 1 + Include/patchlevel.h | 4 ++-- Lib/pydoc_data/topics.py | 2 +- Misc/NEWS | 16 +++++++++++++++- README | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -171,3 +171,4 @@ f3edf13dc339b8942ae6b309771ab197dd8ce6fa v3.6.0a3 017cf260936b444788c9b671d195b7bfd83dbd25 v3.6.0a4 5b0ca4ed5e2f0669d76ece7ef975c544580f12b4 v3.6.0b1 +b9fadc7d1c3f9c3c77f32f35afbe1a1cc38070e6 v3.6.0b2 diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 6 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.6.0b1+" +#define PY_VERSION "3.6.0b2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. 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,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Sep 12 10:47:11 2016 +# Autogenerated by Sphinx on Mon Oct 10 15:59:17 2016 topics = {'assert': '\n' 'The "assert" statement\n' '**********************\n' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,22 @@ Python News +++++++++++ +What's New in Python 3.6.0 beta 3 +================================= + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.6.0 beta 2 ================================= -*Release date: XXXX-XX-XX* +*Release date: 2016-10-10* Core and Builtins ----------------- @@ -266,6 +278,7 @@ - Issue #28217: Adds _testconsole module to test console input. + What's New in Python 3.6.0 beta 1 ================================= @@ -1001,6 +1014,7 @@ - Issue #10910: Avoid C++ compilation errors on FreeBSD and OS X. Also update FreedBSD version checks for the original ctype UTF-8 workaround. + What's New in Python 3.6.0 alpha 3 ================================== diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.6.0 beta 1 +This is Python version 3.6.0 beta 2 =================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 20:58:42 2016 From: python-checkins at python.org (ned.deily) Date: Tue, 11 Oct 2016 00:58:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161011005842.75822.19788.567259DD@psf.io> https://hg.python.org/cpython/rev/cae6808f7fea changeset: 104446:cae6808f7fea parent: 104440:c1960fbb2d96 parent: 104445:cd5f20f75857 user: Ned Deily date: Mon Oct 10 20:56:44 2016 -0400 summary: merge 3.6 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -171,3 +171,4 @@ f3edf13dc339b8942ae6b309771ab197dd8ce6fa v3.6.0a3 017cf260936b444788c9b671d195b7bfd83dbd25 v3.6.0a4 5b0ca4ed5e2f0669d76ece7ef975c544580f12b4 v3.6.0b1 +b9fadc7d1c3f9c3c77f32f35afbe1a1cc38070e6 v3.6.0b2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:30:33 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:30:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI4MjQ4?= =?utf-8?q?=3A_Update_Windows_build_to_use_OpenSSL_1=2E0=2E2j?= Message-ID: <20161011033033.20033.67890.E972C134@psf.io> https://hg.python.org/cpython/rev/d7b9ce8ae79b changeset: 104448:d7b9ce8ae79b branch: 3.4 parent: 104337:8cc1fca83fb8 user: Zachary Ware date: Mon Oct 10 21:57:20 2016 -0500 summary: Issue #28248: Update Windows build to use OpenSSL 1.0.2j files: Misc/NEWS | 5 +++++ PCbuild/get_externals.bat | 2 +- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -32,6 +32,11 @@ - Issue #27759: Fix selectors incorrectly retain invalid file descriptors. Patch by Mark Williams. +Build +----- + +- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. + Tests ----- diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ for %%e in ( bzip2-1.0.6 nasm-2.11.06 - openssl-1.0.2d + openssl-1.0.2j tcl-8.6.1.0 tk-8.6.1.0 tix-8.4.3.4 diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -20,7 +20,7 @@ $(externalsDir)\sqlite-3.8.11.0 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.5 - $(externalsDir)\openssl-1.0.2d + $(externalsDir)\openssl-1.0.2j $(externalsDir)\tcltk $(externalsDir)\tcltk64 $(tcltkDir)\lib\tcl86t.lib;$(tcltkDir)\lib\tk86t.lib diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -171,7 +171,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.2d of the OpenSSL secure sockets + Python wrapper for version 1.0.2j of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:30:33 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:30:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4MjQ4?= =?utf-8?q?=3A_Update_Windows_build_to_use_OpenSSL_1=2E0=2E2j?= Message-ID: <20161011033033.76001.15581.AF9A2553@psf.io> https://hg.python.org/cpython/rev/c29045efd25e changeset: 104447:c29045efd25e branch: 2.7 parent: 104430:de13f5a0f4d5 user: Zachary Ware date: Mon Oct 10 21:57:04 2016 -0500 summary: Issue #28248: Update Windows build to use OpenSSL 1.0.2j files: Misc/NEWS | 2 ++ PC/VS9.0/pyproject.vsprops | 2 +- PC/VS9.0/readme.txt | 2 +- PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -230,6 +230,8 @@ Build ----- +- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. + - Issue #28258: Fixed build with Estonian locale (distclean target in Makefile). Patch by Arfrever Frehtes Taifersar Arahesis. diff --git a/PC/VS9.0/pyproject.vsprops b/PC/VS9.0/pyproject.vsprops --- a/PC/VS9.0/pyproject.vsprops +++ b/PC/VS9.0/pyproject.vsprops @@ -82,7 +82,7 @@ /> $(ExternalsDir)sqlite-3.8.11.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)db-4.7.25.0 - $(ExternalsDir)openssl-1.0.2h\ + $(ExternalsDir)openssl-1.0.2j\ $(opensslDir)include32 $(opensslDir)include64 $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -183,7 +183,7 @@ Homepage: http://www.bzip.org/ _ssl - Python wrapper for version 1.0.2h of the OpenSSL secure sockets + Python wrapper for version 1.0.2j of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:30:34 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:30:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2328248=3A_Merge_with_3=2E4?= Message-ID: <20161011033034.79510.57721.7B0B879F@psf.io> https://hg.python.org/cpython/rev/5fa74d8c987b changeset: 104449:5fa74d8c987b branch: 3.5 parent: 104426:6b1df8905012 parent: 104448:d7b9ce8ae79b user: Zachary Ware date: Mon Oct 10 22:11:12 2016 -0500 summary: Issue #28248: Merge with 3.4 files: Misc/NEWS | 2 ++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -464,6 +464,8 @@ Build ----- +- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. + - Issue #28258: Fixed build with Estonian locale (python-config and distclean targets in Makefile). Patch by Arfrever Frehtes Taifersar Arahesis. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% nasm-2.11.06 -if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2h +if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2j set libraries=%libraries% sqlite-3.8.11.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.4.2 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.4.2 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -46,7 +46,7 @@ $(ExternalsDir)sqlite-3.8.11.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.0.5\ - $(ExternalsDir)openssl-1.0.2h\ + $(ExternalsDir)openssl-1.0.2j\ $(opensslDir)include32 $(opensslDir)include64 $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -169,7 +169,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.2h of the OpenSSL secure sockets + Python wrapper for version 1.0.2j of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:30:34 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:30:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328248=3A_Merge_with_3=2E5?= Message-ID: <20161011033034.94990.54442.D33D0A7A@psf.io> https://hg.python.org/cpython/rev/cc5006dab787 changeset: 104450:cc5006dab787 branch: 3.6 parent: 104445:cd5f20f75857 parent: 104449:5fa74d8c987b user: Zachary Ware date: Mon Oct 10 22:22:27 2016 -0500 summary: Issue #28248: Merge with 3.5 files: Misc/NEWS | 5 +++++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,11 @@ Library ------- +Build +----- + +- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. + What's New in Python 3.6.0 beta 2 ================================= diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% nasm-2.11.06 -if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2h +if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2j set libraries=%libraries% sqlite-3.14.1.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.6.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.6.0 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -45,7 +45,7 @@ $(ExternalsDir)sqlite-3.14.1.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.2.2\ - $(ExternalsDir)openssl-1.0.2h\ + $(ExternalsDir)openssl-1.0.2j\ $(opensslDir)include32 $(opensslDir)include64 $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -169,7 +169,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.2h of the OpenSSL secure sockets + Python wrapper for version 1.0.2j of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:30:34 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:30:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328248=3A_Merge_with_3=2E6?= Message-ID: <20161011033034.94968.42340.11712649@psf.io> https://hg.python.org/cpython/rev/fea9ff9e745d changeset: 104451:fea9ff9e745d parent: 104446:cae6808f7fea parent: 104450:cc5006dab787 user: Zachary Ware date: Mon Oct 10 22:28:39 2016 -0500 summary: Issue #28248: Merge with 3.6 files: Misc/NEWS | 2 ++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -262,6 +262,8 @@ Build ----- +- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. + - Issue #21124: Fix building the _struct module on Cygwin by passing ``NULL`` instead of ``&PyType_Type`` to PyVarObject_HEAD_INIT. Patch by Masayuki Yamamoto. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% nasm-2.11.06 -if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2h +if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2j set libraries=%libraries% sqlite-3.14.1.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.6.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.6.0 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -45,7 +45,7 @@ $(ExternalsDir)sqlite-3.14.1.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.2.2\ - $(ExternalsDir)openssl-1.0.2h\ + $(ExternalsDir)openssl-1.0.2j\ $(opensslDir)include32 $(opensslDir)include64 $(ExternalsDir)\nasm-2.11.06\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -169,7 +169,7 @@ Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.0.2h of the OpenSSL secure sockets + Python wrapper for version 1.0.2j of the OpenSSL secure sockets library, which is built by ssl.vcxproj Homepage: http://www.openssl.org/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:38:03 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:38:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjA4?= =?utf-8?q?=3A_Update_Windows_build_to_use_SQLite_3=2E14=2E2=2E0?= Message-ID: <20161011033803.15562.86787.1A2136D2@psf.io> https://hg.python.org/cpython/rev/b7e068d6c53f changeset: 104452:b7e068d6c53f branch: 3.6 parent: 104450:cc5006dab787 user: Zachary Ware date: Mon Oct 10 22:36:21 2016 -0500 summary: Issue #28208: Update Windows build to use SQLite 3.14.2.0 files: Misc/NEWS | 2 ++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,8 @@ Build ----- +- Issue #28208: Update Windows build to use SQLite 3.14.2.0. + - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -55,7 +55,7 @@ set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% nasm-2.11.06 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2j -set libraries=%libraries% sqlite-3.14.1.0 +set libraries=%libraries% sqlite-3.14.2.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.6.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.6.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -42,7 +42,7 @@ $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals\`)) - $(ExternalsDir)sqlite-3.14.1.0\ + $(ExternalsDir)sqlite-3.14.2.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.2.2\ $(ExternalsDir)openssl-1.0.2j\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -204,7 +204,7 @@ functionality to _ssl or _hashlib. They will not clean up their output with the normal Clean target; CleanAll should be used instead. _sqlite3 - Wraps SQLite 3.14.1.0, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.14.2.0, which is itself built by sqlite3.vcxproj Homepage: http://www.sqlite.org/ _tkinter -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 10 23:38:03 2016 From: python-checkins at python.org (zach.ware) Date: Tue, 11 Oct 2016 03:38:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328208=3A_Merge_with_3=2E6?= Message-ID: <20161011033803.5140.2868.E49CF133@psf.io> https://hg.python.org/cpython/rev/3e329b553567 changeset: 104453:3e329b553567 parent: 104451:fea9ff9e745d parent: 104452:b7e068d6c53f user: Zachary Ware date: Mon Oct 10 22:37:29 2016 -0500 summary: Issue #28208: Merge with 3.6 files: Misc/NEWS | 2 ++ PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -262,6 +262,8 @@ Build ----- +- Issue #28208: Update Windows build to use SQLite 3.14.2.0. + - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. - Issue #21124: Fix building the _struct module on Cygwin by passing ``NULL`` diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -55,7 +55,7 @@ set libraries=%libraries% bzip2-1.0.6 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% nasm-2.11.06 if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2j -set libraries=%libraries% sqlite-3.14.1.0 +set libraries=%libraries% sqlite-3.14.2.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.6.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.6.0 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -42,7 +42,7 @@ $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals\`)) - $(ExternalsDir)sqlite-3.14.1.0\ + $(ExternalsDir)sqlite-3.14.2.0\ $(ExternalsDir)bzip2-1.0.6\ $(ExternalsDir)xz-5.2.2\ $(ExternalsDir)openssl-1.0.2j\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -204,7 +204,7 @@ functionality to _ssl or _hashlib. They will not clean up their output with the normal Clean target; CleanAll should be used instead. _sqlite3 - Wraps SQLite 3.14.1.0, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.14.2.0, which is itself built by sqlite3.vcxproj Homepage: http://www.sqlite.org/ _tkinter -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 11 02:04:21 2016 From: python-checkins at python.org (matthias.klose) Date: Tue, 11 Oct 2016 06:04:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A__-_dictobject=2Ec=3A_Make_?= =?utf-8?q?dict=5Fmerge_symbol_a_static_symbol?= Message-ID: <20161011060421.20873.62115.020E3D50@psf.io> https://hg.python.org/cpython/rev/42b56d8351ee changeset: 104454:42b56d8351ee user: doko at ubuntu.com date: Tue Oct 11 08:04:02 2016 +0200 summary: - dictobject.c: Make dict_merge symbol a static symbol files: Objects/dictobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2372,7 +2372,7 @@ return Py_SAFE_DOWNCAST(i, Py_ssize_t, int); } -int +static int dict_merge(PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 11 02:06:33 2016 From: python-checkins at python.org (matthias.klose) Date: Tue, 11 Oct 2016 06:06:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A__-_Modules/Setup=2Edist=3A?= =?utf-8?q?_Add_the_=5Fblake2_module?= Message-ID: <20161011060633.82059.26807.F7FD3FB8@psf.io> https://hg.python.org/cpython/rev/23802dfd1fca changeset: 104455:23802dfd1fca user: doko at ubuntu.com date: Tue Oct 11 08:06:26 2016 +0200 summary: - Modules/Setup.dist: Add the _blake2 module files: Modules/Setup.dist | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/Setup.dist b/Modules/Setup.dist --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -251,6 +251,8 @@ #_sha256 sha256module.c #_sha512 sha512module.c +# _blake module +#_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c # The _tkinter module. # -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 11 02:21:17 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 11 Oct 2016 06:21:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161011062117.1397.43745.01D70B22@psf.io> https://hg.python.org/cpython/rev/5296d60364ad changeset: 104457:5296d60364ad parent: 104455:23802dfd1fca parent: 104456:032d807039b9 user: Benjamin Peterson date: Mon Oct 10 23:21:10 2016 -0700 summary: merge 3.6 files: Include/pgenheaders.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Include/pgenheaders.h b/Include/pgenheaders.h --- a/Include/pgenheaders.h +++ b/Include/pgenheaders.h @@ -23,6 +23,7 @@ #define delbitset _Py_delbitset #define dumptree _Py_dumptree #define findlabel _Py_findlabel +#define freegrammar _Py_freegrammar #define mergebitset _Py_mergebitset #define meta_grammar _Py_meta_grammar #define newbitset _Py_newbitset -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 11 02:21:17 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 11 Oct 2016 06:21:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_prefix_freegra?= =?utf-8?q?mmar_=28closes_=2328413=29?= Message-ID: <20161011062116.17279.56072.10A224F7@psf.io> https://hg.python.org/cpython/rev/032d807039b9 changeset: 104456:032d807039b9 branch: 3.6 parent: 104452:b7e068d6c53f user: Benjamin Peterson date: Mon Oct 10 23:21:02 2016 -0700 summary: prefix freegrammar (closes #28413) files: Include/pgenheaders.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Include/pgenheaders.h b/Include/pgenheaders.h --- a/Include/pgenheaders.h +++ b/Include/pgenheaders.h @@ -23,6 +23,7 @@ #define delbitset _Py_delbitset #define dumptree _Py_dumptree #define findlabel _Py_findlabel +#define freegrammar _Py_freegrammar #define mergebitset _Py_mergebitset #define meta_grammar _Py_meta_grammar #define newbitset _Py_newbitset -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 11 03:03:43 2016 From: python-checkins at python.org (matthias.klose) Date: Tue, 11 Oct 2016 07:03:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A__-_dictobject?= =?utf-8?q?=2Ec=3A_Make_dict=5Fmerge_symbol_a_static_symbol?= Message-ID: <20161011070343.17319.10679.2AE521D3@psf.io> https://hg.python.org/cpython/rev/8147a150be5e changeset: 104458:8147a150be5e branch: 3.6 parent: 104456:032d807039b9 user: doko at ubuntu.com date: Tue Oct 11 08:04:02 2016 +0200 summary: - dictobject.c: Make dict_merge symbol a static symbol files: Objects/dictobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2372,7 +2372,7 @@ return Py_SAFE_DOWNCAST(i, Py_ssize_t, int); } -int +static int dict_merge(PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 11 03:03:43 2016 From: python-checkins at python.org (matthias.klose) Date: Tue, 11 Oct 2016 07:03:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A__-_Modules/Set?= =?utf-8?q?up=2Edist=3A_Add_the_=5Fblake2_module?= Message-ID: <20161011070343.1522.43502.11E35D5C@psf.io> https://hg.python.org/cpython/rev/685ccab91706 changeset: 104459:685ccab91706 branch: 3.6 user: doko at ubuntu.com date: Tue Oct 11 08:06:26 2016 +0200 summary: - Modules/Setup.dist: Add the _blake2 module files: Modules/Setup.dist | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/Setup.dist b/Modules/Setup.dist --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -251,6 +251,8 @@ #_sha256 sha256module.c #_sha512 sha512module.c +# _blake module +#_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c # The _tkinter module. # -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Tue Oct 11 10:49:22 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 11 Oct 2016 15:49:22 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-11 Message-ID: No new revisions. Here are the previous results: Results for project Python 2.7, build date 2016-10-11 02:47:18 +0000 commit: de13f5a0f4d5 previous commit: 59260b38f7cd revision date: 2016-10-10 01:00:00 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% 0.58% 5.15% 4.75% :-) pybench 0.26% -0.17% 5.93% 4.34% :-( regex_v8 0.69% 0.08% -2.24% 11.29% :-) nbody 0.07% 0.52% 7.99% 3.48% :-) json_dump_v2 0.28% -0.05% 2.89% 9.56% :-| normal_startup 1.07% -0.53% -0.22% 2.35% :-) ssbench 0.28% 0.02% 2.06% 1.45% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-11/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Tue Oct 11 11:05:09 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 11 Oct 2016 16:05:09 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-11 Message-ID: Results for project Python default, build date 2016-10-11 02:01:08 +0000 commit: cae6808f7fea previous commit: 678fe178da0d revision date: 2016-10-11 00:56:44 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-( django_v2 0.25% -3.51% 2.52% 16.95% :-) pybench 0.30% 0.05% 5.50% 4.98% :-( regex_v8 3.73% -0.08% -3.42% 4.02% :-) nbody 0.19% -0.02% 3.50% 3.50% :-( json_dump_v2 0.35% 1.39% -10.41% 14.60% :-) normal_startup 1.05% -0.30% 2.33% 7.38% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-11/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Wed Oct 12 01:42:47 2016 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 12 Oct 2016 05:42:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzE4ODQ0?= =?utf-8?q?=3A__Fix-up_examples_for_random=2Echoices=28=29=2E__Remove_over?= =?utf-8?q?-specified?= Message-ID: <20161012054246.79366.1385.D9E58FC8@psf.io> https://hg.python.org/cpython/rev/433cff92d565 changeset: 104460:433cff92d565 branch: 3.6 user: Raymond Hettinger date: Wed Oct 12 01:42:10 2016 -0400 summary: Issue #18844: Fix-up examples for random.choices(). Remove over-specified test. files: Doc/library/random.rst | 58 +++++++++++++--------------- Lib/test/test_random.py | 4 -- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -131,11 +131,12 @@ If a *weights* sequence is specified, selections are made according to the relative weights. Alternatively, if a *cum_weights* sequence is given, the - selections are made according to the cumulative weights. For example, the - relative weights ``[10, 5, 30, 5]`` are equivalent to the cumulative - weights ``[10, 15, 45, 50]``. Internally, the relative weights are - converted to cumulative weights before making selections, so supplying the - cumulative weights saves work. + selections are made according to the cumulative weights (perhaps computed + using :func:`itertools.accumulate`). For example, the relative weights + ``[10, 5, 30, 5]`` are equivalent to the cumulative weights + ``[10, 15, 45, 50]``. Internally, the relative weights are converted to + cumulative weights before making selections, so supplying the cumulative + weights saves work. If neither *weights* nor *cum_weights* are specified, selections are made with equal probability. If a weights sequence is supplied, it must be @@ -146,6 +147,9 @@ with the :class:`float` values returned by :func:`random` (that includes integers, floats, and fractions but excludes decimals). + .. versionadded:: 3.6 + + .. function:: shuffle(x[, random]) Shuffle the sequence *x* in place. The optional argument *random* is a @@ -335,36 +339,28 @@ >>> random.choice('abcdefghij') # Single random element 'c' - >>> items = [1, 2, 3, 4, 5, 6, 7] - >>> random.shuffle(items) - >>> items - [7, 3, 2, 5, 6, 4, 1] + >>> deck = ['jack', 'queen', 'king', 'ace'] + >>> shuffle(deck) + >>> deck + ['king', 'queen', 'ace', 'jack'] >>> random.sample([1, 2, 3, 4, 5], 3) # Three samples without replacement [4, 1, 5] -A common task is to make a :func:`random.choice` with weighted probabilities. + >>> # Six weighted samples with replacement + >>> choices(['red', 'black', 'green'], [18, 18, 2], k=6) + ['red', 'green', 'black', 'black', 'red', 'black'] -If the weights are small integer ratios, a simple technique is to build a sample -population with repeats:: +Example of `statistical bootstrapping +`_ using resampling +with replacement to estimate a confidence interval for the mean of a small +sample of size five:: - >>> weighted_choices = [('Red', 3), ('Blue', 2), ('Yellow', 1), ('Green', 4)] - >>> population = [val for val, cnt in weighted_choices for i in range(cnt)] - >>> population - ['Red', 'Red', 'Red', 'Blue', 'Blue', 'Yellow', 'Green', 'Green', 'Green', 'Green'] + # http://statistics.about.com/od/Applications/a/Example-Of-Bootstrapping.htm + from statistics import mean + from random import choices - >>> random.choice(population) - 'Green' - -A more general approach is to arrange the weights in a cumulative distribution -with :func:`itertools.accumulate`, and then locate the random value with -:func:`bisect.bisect`:: - - >>> choices, weights = zip(*weighted_choices) - >>> cumdist = list(itertools.accumulate(weights)) - >>> cumdist # [3, 3+2, 3+2+1, 3+2+1+4] - [3, 5, 6, 10] - - >>> x = random.random() * cumdist[-1] - >>> choices[bisect.bisect(cumdist, x)] - 'Blue' + data = 1, 2, 4, 4, 10 + means = sorted(mean(choices(data, k=5)) for i in range(20)) + print('The sample mean of {:.1f} has a 90% confidence interval ' + 'from {:.1f} to {:.1f}'.format(mean(data), means[1], means[-2])) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -178,8 +178,6 @@ self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data)) with self.assertRaises(ValueError): choices(data, [1,2], k=5) # len(weights) != len(population) - with self.assertRaises(IndexError): - choices(data, [0]*4, k=5) # weights sum to zero with self.assertRaises(TypeError): choices(data, 10, k=5) # non-iterable weights with self.assertRaises(TypeError): @@ -194,8 +192,6 @@ with self.assertRaises(ValueError): choices(data, cum_weights=[1,2], k=5) # len(weights) != len(population) - with self.assertRaises(IndexError): - choices(data, cum_weights=[0]*4, k=5) # cum_weights sum to zero with self.assertRaises(TypeError): choices(data, cum_weights=10, k=5) # non-iterable cum_weights with self.assertRaises(TypeError): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 01:42:46 2016 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 12 Oct 2016 05:42:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20161012054246.20229.14335.92B8427F@psf.io> https://hg.python.org/cpython/rev/b96e6efcec0e changeset: 104461:b96e6efcec0e parent: 104457:5296d60364ad parent: 104460:433cff92d565 user: Raymond Hettinger date: Wed Oct 12 01:42:40 2016 -0400 summary: merge files: Doc/library/random.rst | 58 +++++++++++++--------------- Lib/test/test_random.py | 4 -- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -131,11 +131,12 @@ If a *weights* sequence is specified, selections are made according to the relative weights. Alternatively, if a *cum_weights* sequence is given, the - selections are made according to the cumulative weights. For example, the - relative weights ``[10, 5, 30, 5]`` are equivalent to the cumulative - weights ``[10, 15, 45, 50]``. Internally, the relative weights are - converted to cumulative weights before making selections, so supplying the - cumulative weights saves work. + selections are made according to the cumulative weights (perhaps computed + using :func:`itertools.accumulate`). For example, the relative weights + ``[10, 5, 30, 5]`` are equivalent to the cumulative weights + ``[10, 15, 45, 50]``. Internally, the relative weights are converted to + cumulative weights before making selections, so supplying the cumulative + weights saves work. If neither *weights* nor *cum_weights* are specified, selections are made with equal probability. If a weights sequence is supplied, it must be @@ -146,6 +147,9 @@ with the :class:`float` values returned by :func:`random` (that includes integers, floats, and fractions but excludes decimals). + .. versionadded:: 3.6 + + .. function:: shuffle(x[, random]) Shuffle the sequence *x* in place. The optional argument *random* is a @@ -335,36 +339,28 @@ >>> random.choice('abcdefghij') # Single random element 'c' - >>> items = [1, 2, 3, 4, 5, 6, 7] - >>> random.shuffle(items) - >>> items - [7, 3, 2, 5, 6, 4, 1] + >>> deck = ['jack', 'queen', 'king', 'ace'] + >>> shuffle(deck) + >>> deck + ['king', 'queen', 'ace', 'jack'] >>> random.sample([1, 2, 3, 4, 5], 3) # Three samples without replacement [4, 1, 5] -A common task is to make a :func:`random.choice` with weighted probabilities. + >>> # Six weighted samples with replacement + >>> choices(['red', 'black', 'green'], [18, 18, 2], k=6) + ['red', 'green', 'black', 'black', 'red', 'black'] -If the weights are small integer ratios, a simple technique is to build a sample -population with repeats:: +Example of `statistical bootstrapping +`_ using resampling +with replacement to estimate a confidence interval for the mean of a small +sample of size five:: - >>> weighted_choices = [('Red', 3), ('Blue', 2), ('Yellow', 1), ('Green', 4)] - >>> population = [val for val, cnt in weighted_choices for i in range(cnt)] - >>> population - ['Red', 'Red', 'Red', 'Blue', 'Blue', 'Yellow', 'Green', 'Green', 'Green', 'Green'] + # http://statistics.about.com/od/Applications/a/Example-Of-Bootstrapping.htm + from statistics import mean + from random import choices - >>> random.choice(population) - 'Green' - -A more general approach is to arrange the weights in a cumulative distribution -with :func:`itertools.accumulate`, and then locate the random value with -:func:`bisect.bisect`:: - - >>> choices, weights = zip(*weighted_choices) - >>> cumdist = list(itertools.accumulate(weights)) - >>> cumdist # [3, 3+2, 3+2+1, 3+2+1+4] - [3, 5, 6, 10] - - >>> x = random.random() * cumdist[-1] - >>> choices[bisect.bisect(cumdist, x)] - 'Blue' + data = 1, 2, 4, 4, 10 + means = sorted(mean(choices(data, k=5)) for i in range(20)) + print('The sample mean of {:.1f} has a 90% confidence interval ' + 'from {:.1f} to {:.1f}'.format(mean(data), means[1], means[-2])) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -178,8 +178,6 @@ self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data)) with self.assertRaises(ValueError): choices(data, [1,2], k=5) # len(weights) != len(population) - with self.assertRaises(IndexError): - choices(data, [0]*4, k=5) # weights sum to zero with self.assertRaises(TypeError): choices(data, 10, k=5) # non-iterable weights with self.assertRaises(TypeError): @@ -194,8 +192,6 @@ with self.assertRaises(ValueError): choices(data, cum_weights=[1,2], k=5) # len(weights) != len(population) - with self.assertRaises(IndexError): - choices(data, cum_weights=[0]*4, k=5) # cum_weights sum to zero with self.assertRaises(TypeError): choices(data, cum_weights=10, k=5) # non-iterable cum_weights with self.assertRaises(TypeError): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 02:01:20 2016 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 12 Oct 2016 06:01:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogdmFfZW5kIHZhcmdz?= =?utf-8?q?2_once_=28closes_=2328417=29?= Message-ID: <20161012060120.85616.35074.67BBF9FF@psf.io> https://hg.python.org/cpython/rev/6a6ac890db78 changeset: 104462:6a6ac890db78 branch: 3.6 parent: 104460:433cff92d565 user: Benjamin Peterson date: Tue Oct 11 23:00:58 2016 -0700 summary: va_end vargs2 once (closes #28417) files: Objects/unicodeobject.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2895,7 +2895,6 @@ do { if ((unsigned char)*p > 127) { - va_end(vargs2); PyErr_Format(PyExc_ValueError, "PyUnicode_FromFormatV() expects an ASCII-encoded format " "string, got a non-ASCII byte: 0x%02x", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 02:01:20 2016 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 12 Oct 2016 06:01:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42ICgjMjg0MTcp?= Message-ID: <20161012060120.82076.26064.835E341A@psf.io> https://hg.python.org/cpython/rev/439427ffbba1 changeset: 104463:439427ffbba1 parent: 104461:b96e6efcec0e parent: 104462:6a6ac890db78 user: Benjamin Peterson date: Tue Oct 11 23:01:12 2016 -0700 summary: merge 3.6 (#28417) files: Objects/unicodeobject.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2891,7 +2891,6 @@ do { if ((unsigned char)*p > 127) { - va_end(vargs2); PyErr_Format(PyExc_ValueError, "PyUnicode_FromFormatV() expects an ASCII-encoded format " "string, got a non-ASCII byte: 0x%02x", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 07:59:37 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 12 Oct 2016 11:59:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogRml4IF9QeV9ub3Jt?= =?utf-8?q?alize=5Fencoding=28=29_command?= Message-ID: <20161012115937.75952.66945.645E9A3E@psf.io> https://hg.python.org/cpython/rev/ac2f7cfff9a2 changeset: 104464:ac2f7cfff9a2 branch: 3.6 parent: 104462:6a6ac890db78 user: Victor Stinner date: Wed Oct 12 13:57:45 2016 +0200 summary: Fix _Py_normalize_encoding() command It's not exactly the same than encodings.normalize_encoding(): the C function also converts to lowercase. files: Objects/unicodeobject.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3100,9 +3100,9 @@ return v; } -/* Normalize an encoding name: C implementation of - encodings.normalize_encoding(). Return 1 on success, or 0 on error (encoding - is longer than lower_len-1). */ +/* Normalize an encoding name: similar to encodings.normalize_encoding(), but + also convert to lowercase. Return 1 on success, or 0 on error (encoding is + longer than lower_len-1). */ int _Py_normalize_encoding(const char *encoding, char *lower, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 07:59:37 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 12 Oct 2016 11:59:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42?= Message-ID: <20161012115937.75928.25871.33EBC21B@psf.io> https://hg.python.org/cpython/rev/454f6eee1bd7 changeset: 104465:454f6eee1bd7 parent: 104463:439427ffbba1 parent: 104464:ac2f7cfff9a2 user: Victor Stinner date: Wed Oct 12 13:59:13 2016 +0200 summary: Merge 3.6 files: Objects/unicodeobject.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3096,9 +3096,9 @@ return v; } -/* Normalize an encoding name: C implementation of - encodings.normalize_encoding(). Return 1 on success, or 0 on error (encoding - is longer than lower_len-1). */ +/* Normalize an encoding name: similar to encodings.normalize_encoding(), but + also convert to lowercase. Return 1 on success, or 0 on error (encoding is + longer than lower_len-1). */ int _Py_normalize_encoding(const char *encoding, char *lower, -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Wed Oct 12 13:37:09 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 12 Oct 2016 18:37:09 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-12 Message-ID: <26ab5b7b-2963-4434-b25c-6cb1234a149d@irsmsx101.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-12 02:47:00 +0000 commit: c29045efd25e previous commit: de13f5a0f4d5 revision date: 2016-10-11 02:57:04 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.15% 0.74% 5.85% 3.07% :-) pybench 0.17% 0.14% 6.06% 2.64% :-( regex_v8 0.69% 0.06% -2.18% 11.12% :-) nbody 0.07% 0.03% 8.01% 2.79% :-) json_dump_v2 0.25% -0.04% 2.84% 10.88% :-| normal_startup 1.31% 0.45% 0.23% 1.89% :-) ssbench 0.28% 0.45% 2.52% 1.19% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-12/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Wed Oct 12 13:38:06 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 12 Oct 2016 18:38:06 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-12 Message-ID: Results for project Python default, build date 2016-10-12 02:01:13 +0000 commit: 5296d60364ad previous commit: cae6808f7fea revision date: 2016-10-11 06:21:10 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.19% 3.88% 6.30% 15.55% :-) pybench 0.12% -0.21% 5.31% 5.38% :-( regex_v8 3.71% 0.00% -3.42% 4.11% :-) nbody 0.40% -0.28% 3.23% 5.39% :-( json_dump_v2 0.30% -0.07% -10.49% 15.49% :-) normal_startup 1.22% 1.43% 4.20% 5.59% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-12/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Wed Oct 12 14:19:32 2016 From: python-checkins at python.org (xavier.degaye) Date: Wed, 12 Oct 2016 18:19:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2320766=3A_Merge_with_3=2E5=2E?= Message-ID: <20161012181931.5225.40877.0888A3B3@psf.io> https://hg.python.org/cpython/rev/86a1905ea28d changeset: 104467:86a1905ea28d branch: 3.6 parent: 104464:ac2f7cfff9a2 parent: 104466:31a2d270c0c3 user: Xavier de Gaye date: Wed Oct 12 20:16:05 2016 +0200 summary: Issue #20766: Merge with 3.5. files: Lib/pdb.py | 10 +++++++--- Lib/test/test_pdb.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -135,6 +135,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): + _previous_sigint_handler = None + def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True): bdb.Bdb.__init__(self, skip=skip) @@ -189,8 +191,6 @@ self.message("\nProgram interrupted. (Use 'cont' to resume).") self.set_step() self.set_trace(frame) - # restore previous signal handler - signal.signal(signal.SIGINT, self._previous_sigint_handler) def reset(self): bdb.Bdb.reset(self) @@ -339,6 +339,10 @@ (expr, newvalue, oldvalue)) def interaction(self, frame, traceback): + # Restore the previous signal handler at the Pdb prompt. + if Pdb._previous_sigint_handler: + signal.signal(signal.SIGINT, Pdb._previous_sigint_handler) + Pdb._previous_sigint_handler = None if self.setup(frame, traceback): # no interaction desired at this time (happens if .pdbrc contains # a command like "continue") @@ -1039,7 +1043,7 @@ """ if not self.nosigint: try: - self._previous_sigint_handler = \ + Pdb._previous_sigint_handler = \ signal.signal(signal.SIGINT, self.sigint_handler) except ValueError: # ValueError happens when do_continue() is invoked from diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -911,6 +911,29 @@ (Pdb) continue """ +def test_pdb_issue_20766(): + """Test for reference leaks when the SIGINT handler is set. + + >>> def test_function(): + ... i = 1 + ... while i <= 2: + ... sess = pdb.Pdb() + ... sess.set_trace(sys._getframe()) + ... print('pdb %d: %s' % (i, sess._previous_sigint_handler)) + ... i += 1 + + >>> with PdbTestInput(['continue', + ... 'continue']): + ... test_function() + > (6)test_function() + -> print('pdb %d: %s' % (i, sess._previous_sigint_handler)) + (Pdb) continue + pdb 1: + > (5)test_function() + -> sess.set_trace(sys._getframe()) + (Pdb) continue + pdb 2: + """ class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #20766: Fix references leaked by pdb in the handling of SIGINT + handlers. + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 14:19:32 2016 From: python-checkins at python.org (xavier.degaye) Date: Wed, 12 Oct 2016 18:19:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIwNzY2?= =?utf-8?q?=3A_Fix_references_leaked_by_pdb_in_the_handling_of_SIGINT_hand?= =?utf-8?q?lers=2E?= Message-ID: <20161012181931.79344.26235.9EF8CED7@psf.io> https://hg.python.org/cpython/rev/31a2d270c0c3 changeset: 104466:31a2d270c0c3 branch: 3.5 parent: 104449:5fa74d8c987b user: Xavier de Gaye date: Wed Oct 12 20:13:24 2016 +0200 summary: Issue #20766: Fix references leaked by pdb in the handling of SIGINT handlers. files: Lib/pdb.py | 10 +++++++--- Lib/test/test_pdb.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -134,6 +134,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): + _previous_sigint_handler = None + def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False): bdb.Bdb.__init__(self, skip=skip) @@ -187,8 +189,6 @@ self.message("\nProgram interrupted. (Use 'cont' to resume).") self.set_step() self.set_trace(frame) - # restore previous signal handler - signal.signal(signal.SIGINT, self._previous_sigint_handler) def reset(self): bdb.Bdb.reset(self) @@ -337,6 +337,10 @@ (expr, newvalue, oldvalue)) def interaction(self, frame, traceback): + # Restore the previous signal handler at the Pdb prompt. + if Pdb._previous_sigint_handler: + signal.signal(signal.SIGINT, Pdb._previous_sigint_handler) + Pdb._previous_sigint_handler = None if self.setup(frame, traceback): # no interaction desired at this time (happens if .pdbrc contains # a command like "continue") @@ -1037,7 +1041,7 @@ """ if not self.nosigint: try: - self._previous_sigint_handler = \ + Pdb._previous_sigint_handler = \ signal.signal(signal.SIGINT, self.sigint_handler) except ValueError: # ValueError happens when do_continue() is invoked from diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -911,6 +911,29 @@ (Pdb) continue """ +def test_pdb_issue_20766(): + """Test for reference leaks when the SIGINT handler is set. + + >>> def test_function(): + ... i = 1 + ... while i <= 2: + ... sess = pdb.Pdb() + ... sess.set_trace(sys._getframe()) + ... print('pdb %d: %s' % (i, sess._previous_sigint_handler)) + ... i += 1 + + >>> with PdbTestInput(['continue', + ... 'continue']): + ... test_function() + > (6)test_function() + -> print('pdb %d: %s' % (i, sess._previous_sigint_handler)) + (Pdb) continue + pdb 1: + > (5)test_function() + -> sess.set_trace(sys._getframe()) + (Pdb) continue + pdb 2: + """ class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -107,6 +107,9 @@ Library ------- +- Issue #20766: Fix references leaked by pdb in the handling of SIGINT + handlers. + - Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 12 14:19:33 2016 From: python-checkins at python.org (xavier.degaye) Date: Wed, 12 Oct 2016 18:19:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320766=3A_Merge_with_3=2E6=2E?= Message-ID: <20161012181933.85988.75048.9B1FC00D@psf.io> https://hg.python.org/cpython/rev/8bb426d386a5 changeset: 104468:8bb426d386a5 parent: 104465:454f6eee1bd7 parent: 104467:86a1905ea28d user: Xavier de Gaye date: Wed Oct 12 20:18:33 2016 +0200 summary: Issue #20766: Merge with 3.6. files: Lib/pdb.py | 10 +++++++--- Lib/test/test_pdb.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -135,6 +135,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): + _previous_sigint_handler = None + def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True): bdb.Bdb.__init__(self, skip=skip) @@ -189,8 +191,6 @@ self.message("\nProgram interrupted. (Use 'cont' to resume).") self.set_step() self.set_trace(frame) - # restore previous signal handler - signal.signal(signal.SIGINT, self._previous_sigint_handler) def reset(self): bdb.Bdb.reset(self) @@ -339,6 +339,10 @@ (expr, newvalue, oldvalue)) def interaction(self, frame, traceback): + # Restore the previous signal handler at the Pdb prompt. + if Pdb._previous_sigint_handler: + signal.signal(signal.SIGINT, Pdb._previous_sigint_handler) + Pdb._previous_sigint_handler = None if self.setup(frame, traceback): # no interaction desired at this time (happens if .pdbrc contains # a command like "continue") @@ -1039,7 +1043,7 @@ """ if not self.nosigint: try: - self._previous_sigint_handler = \ + Pdb._previous_sigint_handler = \ signal.signal(signal.SIGINT, self.sigint_handler) except ValueError: # ValueError happens when do_continue() is invoked from diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -911,6 +911,29 @@ (Pdb) continue """ +def test_pdb_issue_20766(): + """Test for reference leaks when the SIGINT handler is set. + + >>> def test_function(): + ... i = 1 + ... while i <= 2: + ... sess = pdb.Pdb() + ... sess.set_trace(sys._getframe()) + ... print('pdb %d: %s' % (i, sess._previous_sigint_handler)) + ... i += 1 + + >>> with PdbTestInput(['continue', + ... 'continue']): + ... test_function() + > (6)test_function() + -> print('pdb %d: %s' % (i, sess._previous_sigint_handler)) + (Pdb) continue + pdb 1: + > (5)test_function() + -> sess.set_trace(sys._getframe()) + (Pdb) continue + pdb 2: + """ class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,9 @@ Library ------- +- Issue #20766: Fix references leaked by pdb in the handling of SIGINT + handlers. + - Issue #27998: Fixed bytes path support in os.scandir() on Windows. Patch by Eryk Sun. -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Thu Oct 13 10:39:06 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 13 Oct 2016 15:39:06 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-13 Message-ID: No new revisions. Here are the previous results: Results for project Python 2.7, build date 2016-10-13 02:47:51 +0000 commit: c29045efd25e previous commit: de13f5a0f4d5 revision date: 2016-10-11 02:57:04 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.15% 0.74% 5.85% 3.07% :-) pybench 0.17% 0.14% 6.06% 2.64% :-( regex_v8 0.69% 0.06% -2.18% 11.12% :-) nbody 0.07% 0.03% 8.01% 2.79% :-) json_dump_v2 0.25% -0.04% 2.84% 10.88% :-| normal_startup 1.31% 0.45% 0.23% 1.89% :-) ssbench 0.28% 0.45% 2.52% 1.19% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-13/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Thu Oct 13 10:39:27 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 13 Oct 2016 15:39:27 +0100 Subject: [Python-checkins] BAD Benchmark Results for Python Default 2016-10-13 Message-ID: Results for project Python default, build date 2016-10-13 02:01:37 +0000 commit: 8bb426d386a5 previous commit: 5296d60364ad revision date: 2016-10-12 18:18:33 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.21% -2.63% 3.84% 17.49% :-) pybench 0.11% 0.14% 5.44% 4.43% :-( regex_v8 3.69% 0.02% -3.40% 3.94% :-) nbody 0.09% 0.11% 3.34% 4.37% :-( json_dump_v2 0.27% 0.02% -10.47% 16.99% :-) normal_startup 0.49% -1.61% 2.03% 6.32% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/bad-benchmark-results-for-python-default-2016-10-13/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Thu Oct 13 14:22:59 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 18:22:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0NDUy?= =?utf-8?q?=3A_Make_webbrowser_support_Chrome_on_Mac_OS_X=2E?= Message-ID: <20161013182259.1397.59424.E028EBA2@psf.io> https://hg.python.org/cpython/rev/bd0f502c5eea changeset: 104469:bd0f502c5eea branch: 3.5 parent: 104466:31a2d270c0c3 user: Guido van Rossum date: Thu Oct 13 11:17:27 2016 -0700 summary: Issue #24452: Make webbrowser support Chrome on Mac OS X. files: Lib/webbrowser.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -600,6 +600,7 @@ # (but we prefer using the OS X specific stuff) register("safari", None, MacOSXOSAScript('safari'), -1) register("firefox", None, MacOSXOSAScript('firefox'), -1) + register("chrome", None, MacOSXOSAScript('chrome'), -1) register("MacOSX", None, MacOSXOSAScript('default'), -1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -107,6 +107,8 @@ Library ------- +- Issue #24452: Make webbrowser support Chrome on Mac OS X. + - Issue #20766: Fix references leaked by pdb in the handling of SIGINT handlers. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 14:23:00 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 18:23:00 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2324452=3A_Make_webbrowser_support_Chrome_on_Mac_OS_X_?= =?utf-8?b?KG1lcmdlIDMuNS0+My42KQ==?= Message-ID: <20161013182259.95738.44364.46055F68@psf.io> https://hg.python.org/cpython/rev/64a38f9aee21 changeset: 104470:64a38f9aee21 branch: 3.6 parent: 104467:86a1905ea28d parent: 104469:bd0f502c5eea user: Guido van Rossum date: Thu Oct 13 11:22:52 2016 -0700 summary: Issue #24452: Make webbrowser support Chrome on Mac OS X (merge 3.5->3.6) files: Lib/webbrowser.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -600,6 +600,7 @@ # (but we prefer using the OS X specific stuff) register("safari", None, MacOSXOSAScript('safari'), -1) register("firefox", None, MacOSXOSAScript('firefox'), -1) + register("chrome", None, MacOSXOSAScript('chrome'), -1) register("MacOSX", None, MacOSXOSAScript('default'), -1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #24452: Make webbrowser support Chrome on Mac OS X. + - Issue #20766: Fix references leaked by pdb in the handling of SIGINT handlers. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 14:25:33 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 18:25:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324452=3A_Make_webbrowser_support_Chrome_on_Mac_?= =?utf-8?b?T1MgWCAobWVyZ2UgMy42LT4zLjcp?= Message-ID: <20161013182532.111418.83584.75050721@psf.io> https://hg.python.org/cpython/rev/4e2cce65e522 changeset: 104471:4e2cce65e522 parent: 104468:8bb426d386a5 parent: 104470:64a38f9aee21 user: Guido van Rossum date: Thu Oct 13 11:25:17 2016 -0700 summary: Issue #24452: Make webbrowser support Chrome on Mac OS X (merge 3.6->3.7) files: Lib/webbrowser.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -600,6 +600,7 @@ # (but we prefer using the OS X specific stuff) register("safari", None, MacOSXOSAScript('safari'), -1) register("firefox", None, MacOSXOSAScript('firefox'), -1) + register("chrome", None, MacOSXOSAScript('chrome'), -1) register("MacOSX", None, MacOSXOSAScript('default'), -1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,8 @@ Library ------- +- Issue #24452: Make webbrowser support Chrome on Mac OS X. + - Issue #20766: Fix references leaked by pdb in the handling of SIGINT handlers. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 15:10:56 2016 From: python-checkins at python.org (christian.heimes) Date: Thu, 13 Oct 2016 19:10:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Check_return_v?= =?utf-8?q?alue_of_=5FPyDict=5FSetItemId=28=29?= Message-ID: <20161013191052.15320.79538.40FA1FEC@psf.io> https://hg.python.org/cpython/rev/fa6767289ce6 changeset: 104472:fa6767289ce6 branch: 3.6 parent: 104470:64a38f9aee21 user: Christian Heimes date: Thu Oct 13 21:10:31 2016 +0200 summary: Check return value of _PyDict_SetItemId() files: Objects/typeobject.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2848,13 +2848,16 @@ /* Set type.__module__ */ s = strrchr(spec->name, '.'); if (s != NULL) { + int err; modname = PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name)); if (modname == NULL) { goto fail; } - _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); Py_DECREF(modname); + if (err != 0) + goto fail; } else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "builtin type %.200s has no __module__ attribute", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 15:10:56 2016 From: python-checkins at python.org (christian.heimes) Date: Thu, 13 Oct 2016 19:10:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Check_return_value_of_=5FPyDict=5FSetItemId=28=29?= Message-ID: <20161013191052.17279.50724.12635D9F@psf.io> https://hg.python.org/cpython/rev/c78770ae8442 changeset: 104473:c78770ae8442 parent: 104471:4e2cce65e522 parent: 104472:fa6767289ce6 user: Christian Heimes date: Thu Oct 13 21:10:42 2016 +0200 summary: Check return value of _PyDict_SetItemId() files: Objects/typeobject.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2848,13 +2848,16 @@ /* Set type.__module__ */ s = strrchr(spec->name, '.'); if (s != NULL) { + int err; modname = PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name)); if (modname == NULL) { goto fail; } - _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); Py_DECREF(modname); + if (err != 0) + goto fail; } else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "builtin type %.200s has no __module__ attribute", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 16:30:26 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 20:30:26 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0NDUy?= =?utf-8?q?=3A_Make_webbrowser_support_Chrome_on_Mac_OS_X_=28backport_to_2?= =?utf-8?b?Ljcp?= Message-ID: <20161013203025.10701.71594.E7AABA2B@psf.io> https://hg.python.org/cpython/rev/bc8a4b121aec changeset: 104474:bc8a4b121aec branch: 2.7 parent: 104447:c29045efd25e user: Guido van Rossum date: Thu Oct 13 13:29:55 2016 -0700 summary: Issue #24452: Make webbrowser support Chrome on Mac OS X (backport to 2.7) files: Lib/webbrowser.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -642,6 +642,7 @@ # (but we prefer using the OS X specific stuff) register("safari", None, MacOSXOSAScript('safari'), -1) register("firefox", None, MacOSXOSAScript('firefox'), -1) + register("chrome", None, MacOSXOSAScript('chrome'), -1) register("MacOSX", None, MacOSXOSAScript('default'), -1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,8 @@ Library ------- +- Issue #24452: Make webbrowser support Chrome on Mac OS X. + - Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 16:57:53 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 20:57:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIxNDQz?= =?utf-8?q?=3A_Show_how_to_change_log_level_for_asyncio=2E?= Message-ID: <20161013205752.43967.41453.E97C009F@psf.io> https://hg.python.org/cpython/rev/e68b1b2515e9 changeset: 104475:e68b1b2515e9 branch: 3.5 parent: 104469:bd0f502c5eea user: Guido van Rossum date: Thu Oct 13 13:56:40 2016 -0700 summary: Issue #21443: Show how to change log level for asyncio. files: Doc/library/asyncio-dev.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -161,6 +161,14 @@ The :mod:`asyncio` module logs information with the :mod:`logging` module in the logger ``'asyncio'``. +The default log level for the :mod:`asyncio` module is :py:data:`logging.INFO`. +For those not wanting such verbosity from :mod:`asyncio` the log level can +be changed. For example, to change the level to :py:data:`logging.WARNING`: + +.. code-block:: none + + logging.getLogger('asyncio').setLevel(logging.WARNING) + .. _asyncio-coroutine-not-scheduled: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 16:57:53 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 20:57:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2321443=3A_Show_how_to_change_log_level_for_asyncio=2E_?= =?utf-8?b?KE1lcmdlIDMuNS0+My42KQ==?= Message-ID: <20161013205753.82711.4845.60FB4515@psf.io> https://hg.python.org/cpython/rev/660058d76788 changeset: 104476:660058d76788 branch: 3.6 parent: 104472:fa6767289ce6 parent: 104475:e68b1b2515e9 user: Guido van Rossum date: Thu Oct 13 13:57:17 2016 -0700 summary: Issue #21443: Show how to change log level for asyncio. (Merge 3.5->3.6) files: Doc/library/asyncio-dev.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -161,6 +161,14 @@ The :mod:`asyncio` module logs information with the :mod:`logging` module in the logger ``'asyncio'``. +The default log level for the :mod:`asyncio` module is :py:data:`logging.INFO`. +For those not wanting such verbosity from :mod:`asyncio` the log level can +be changed. For example, to change the level to :py:data:`logging.WARNING`: + +.. code-block:: none + + logging.getLogger('asyncio').setLevel(logging.WARNING) + .. _asyncio-coroutine-not-scheduled: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 16:58:07 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 20:58:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2321443=3A_Show_how_to_change_log_level_for_async?= =?utf-8?b?aW8uIChNZXJnZSAzLjYtPjMuNyk=?= Message-ID: <20161013205753.20329.88825.C83ECA58@psf.io> https://hg.python.org/cpython/rev/861d22bd852d changeset: 104477:861d22bd852d parent: 104473:c78770ae8442 parent: 104476:660058d76788 user: Guido van Rossum date: Thu Oct 13 13:57:39 2016 -0700 summary: Issue #21443: Show how to change log level for asyncio. (Merge 3.6->3.7) files: Doc/library/asyncio-dev.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -161,6 +161,14 @@ The :mod:`asyncio` module logs information with the :mod:`logging` module in the logger ``'asyncio'``. +The default log level for the :mod:`asyncio` module is :py:data:`logging.INFO`. +For those not wanting such verbosity from :mod:`asyncio` the log level can +be changed. For example, to change the level to :py:data:`logging.WARNING`: + +.. code-block:: none + + logging.getLogger('asyncio').setLevel(logging.WARNING) + .. _asyncio-coroutine-not-scheduled: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:24:54 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:24:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2326869=3A_Document_unittest=2ETestCase=2ElongMessage?= =?utf-8?b?LiAoTWFyaWF0dGEpICgzLjUtPjMuNik=?= Message-ID: <20161013212453.98866.61646.6625991C@psf.io> https://hg.python.org/cpython/rev/d7279d803d1d changeset: 104479:d7279d803d1d branch: 3.6 parent: 104476:660058d76788 parent: 104478:7eb4fe57492f user: Guido van Rossum date: Thu Oct 13 14:24:23 2016 -0700 summary: Issue #26869: Document unittest.TestCase.longMessage. (Mariatta) (3.5->3.6) files: Doc/library/unittest.rst | 24 +++++++++++------------- 1 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1316,19 +1316,17 @@ .. attribute:: longMessage - If set to ``True`` then any explicit failure message you pass in to the - :ref:`assert methods ` will be appended to the end of the - normal failure message. The normal messages contain useful information - about the objects involved, for example the message from assertEqual - shows you the repr of the two unequal objects. Setting this attribute - to ``True`` allows you to have a custom error message in addition to the - normal one. - - This attribute defaults to ``True``. If set to False then a custom message - passed to an assert method will silence the normal message. - - The class setting can be overridden in individual tests by assigning an - instance attribute to ``True`` or ``False`` before calling the assert methods. + This class attribute determines what happens when a custom failure message + is passed as the msg argument to an assertXYY call that fails. + ``True`` is the default value. In this case, the custom message is appended + to the end of the standard failure message. + When set to ``False``, the custom message replaces the standard message. + + The class setting can be overridden in individual test methods by assigning + an instance attribute, self.longMessage, to ``True`` or ``False`` before + calling the assert methods. + + The class setting gets reset before each test call. .. versionadded:: 3.1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:24:54 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:24:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326869=3A_Document_unittest=2ETestCase=2ElongMes?= =?utf-8?b?c2FnZS4gKE1hcmlhdHRhKSAoMy42LT4zLjcp?= Message-ID: <20161013212453.43869.28523.E45C8CAD@psf.io> https://hg.python.org/cpython/rev/c7c428350578 changeset: 104480:c7c428350578 parent: 104477:861d22bd852d parent: 104479:d7279d803d1d user: Guido van Rossum date: Thu Oct 13 14:24:47 2016 -0700 summary: Issue #26869: Document unittest.TestCase.longMessage. (Mariatta) (3.6->3.7) files: Doc/library/unittest.rst | 24 +++++++++++------------- 1 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1316,19 +1316,17 @@ .. attribute:: longMessage - If set to ``True`` then any explicit failure message you pass in to the - :ref:`assert methods ` will be appended to the end of the - normal failure message. The normal messages contain useful information - about the objects involved, for example the message from assertEqual - shows you the repr of the two unequal objects. Setting this attribute - to ``True`` allows you to have a custom error message in addition to the - normal one. - - This attribute defaults to ``True``. If set to False then a custom message - passed to an assert method will silence the normal message. - - The class setting can be overridden in individual tests by assigning an - instance attribute to ``True`` or ``False`` before calling the assert methods. + This class attribute determines what happens when a custom failure message + is passed as the msg argument to an assertXYY call that fails. + ``True`` is the default value. In this case, the custom message is appended + to the end of the standard failure message. + When set to ``False``, the custom message replaces the standard message. + + The class setting can be overridden in individual test methods by assigning + an instance attribute, self.longMessage, to ``True`` or ``False`` before + calling the assert methods. + + The class setting gets reset before each test call. .. versionadded:: 3.1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:33:11 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:33:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318789=3A_Update_XML_vulnerability_table_to_use_?= =?utf-8?q?Safe/Vulnerable_instead_of?= Message-ID: <20161013213301.17526.72166.903BF7D1@psf.io> https://hg.python.org/cpython/rev/9513fac97ddd changeset: 104483:9513fac97ddd parent: 104480:c7c428350578 parent: 104482:beed43d7dc46 user: Guido van Rossum date: Thu Oct 13 14:32:55 2016 -0700 summary: Issue #18789: Update XML vulnerability table to use Safe/Vulnerable instead of No/Yes. (3.6->3.7) files: Doc/library/xml.rst | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -60,15 +60,15 @@ The following table gives an overview of the known attacks and whether the various modules are vulnerable to them. -========================= ======== ========= ========= ======== ========= -kind sax etree minidom pulldom xmlrpc -========================= ======== ========= ========= ======== ========= -billion laughs **Yes** **Yes** **Yes** **Yes** **Yes** -quadratic blowup **Yes** **Yes** **Yes** **Yes** **Yes** -external entity expansion **Yes** No (1) No (2) **Yes** No (3) -`DTD`_ retrieval **Yes** No No **Yes** No -decompression bomb No No No No **Yes** -========================= ======== ========= ========= ======== ========= +========================= ============== =============== ============== ============== ============== +kind sax etree minidom pulldom xmlrpc +========================= ============== =============== ============== ============== ============== +billion laughs **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +quadratic blowup **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +external entity expansion **Vulnerable** Safe (1) Safe (2) **Vulnerable** Safe (3) +`DTD`_ retrieval **Vulnerable** Safe Safe **Vulnerable** Safe +decompression bomb Safe Safe Safe Safe **Vulnerable** +========================= ============== =============== ============== ============== ============== 1. :mod:`xml.etree.ElementTree` doesn't expand external entities and raises a :exc:`ParserError` when an entity occurs. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:33:11 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:33:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2318789=3A_Update_XML_vulnerability_table_to_use_Safe/V?= =?utf-8?q?ulnerable_instead_of?= Message-ID: <20161013213301.17468.14702.01DACBA8@psf.io> https://hg.python.org/cpython/rev/beed43d7dc46 changeset: 104482:beed43d7dc46 branch: 3.6 parent: 104479:d7279d803d1d parent: 104481:e05c546062a1 user: Guido van Rossum date: Thu Oct 13 14:32:33 2016 -0700 summary: Issue #18789: Update XML vulnerability table to use Safe/Vulnerable instead of No/Yes. (3.5->3.6) files: Doc/library/xml.rst | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -60,15 +60,15 @@ The following table gives an overview of the known attacks and whether the various modules are vulnerable to them. -========================= ======== ========= ========= ======== ========= -kind sax etree minidom pulldom xmlrpc -========================= ======== ========= ========= ======== ========= -billion laughs **Yes** **Yes** **Yes** **Yes** **Yes** -quadratic blowup **Yes** **Yes** **Yes** **Yes** **Yes** -external entity expansion **Yes** No (1) No (2) **Yes** No (3) -`DTD`_ retrieval **Yes** No No **Yes** No -decompression bomb No No No No **Yes** -========================= ======== ========= ========= ======== ========= +========================= ============== =============== ============== ============== ============== +kind sax etree minidom pulldom xmlrpc +========================= ============== =============== ============== ============== ============== +billion laughs **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +quadratic blowup **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +external entity expansion **Vulnerable** Safe (1) Safe (2) **Vulnerable** Safe (3) +`DTD`_ retrieval **Vulnerable** Safe Safe **Vulnerable** Safe +decompression bomb Safe Safe Safe Safe **Vulnerable** +========================= ============== =============== ============== ============== ============== 1. :mod:`xml.etree.ElementTree` doesn't expand external entities and raises a :exc:`ParserError` when an entity occurs. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:33:11 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:33:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2ODY5?= =?utf-8?q?=3A_Document_unittest=2ETestCase=2ElongMessage=2E_=28Mariatta?= =?utf-8?q?=29?= Message-ID: <20161013212453.20673.49279.A377F9B6@psf.io> https://hg.python.org/cpython/rev/7eb4fe57492f changeset: 104478:7eb4fe57492f branch: 3.5 parent: 104475:e68b1b2515e9 user: Guido van Rossum date: Thu Oct 13 14:23:01 2016 -0700 summary: Issue #26869: Document unittest.TestCase.longMessage. (Mariatta) files: Doc/library/unittest.rst | 24 +++++++++++------------- 1 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1316,19 +1316,17 @@ .. attribute:: longMessage - If set to ``True`` then any explicit failure message you pass in to the - :ref:`assert methods ` will be appended to the end of the - normal failure message. The normal messages contain useful information - about the objects involved, for example the message from assertEqual - shows you the repr of the two unequal objects. Setting this attribute - to ``True`` allows you to have a custom error message in addition to the - normal one. - - This attribute defaults to ``True``. If set to False then a custom message - passed to an assert method will silence the normal message. - - The class setting can be overridden in individual tests by assigning an - instance attribute to ``True`` or ``False`` before calling the assert methods. + This class attribute determines what happens when a custom failure message + is passed as the msg argument to an assertXYY call that fails. + ``True`` is the default value. In this case, the custom message is appended + to the end of the standard failure message. + When set to ``False``, the custom message replaces the standard message. + + The class setting can be overridden in individual test methods by assigning + an instance attribute, self.longMessage, to ``True`` or ``False`` before + calling the assert methods. + + The class setting gets reset before each test call. .. versionadded:: 3.1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:33:11 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:33:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE4Nzg5?= =?utf-8?q?=3A_Update_XML_vulnerability_table_to_use_Safe/Vulnerable_inste?= =?utf-8?q?ad_of?= Message-ID: <20161013213301.17363.29834.38A2E0FE@psf.io> https://hg.python.org/cpython/rev/e05c546062a1 changeset: 104481:e05c546062a1 branch: 3.5 parent: 104478:7eb4fe57492f user: Guido van Rossum date: Thu Oct 13 14:31:50 2016 -0700 summary: Issue #18789: Update XML vulnerability table to use Safe/Vulnerable instead of No/Yes. files: Doc/library/xml.rst | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -60,15 +60,15 @@ The following table gives an overview of the known attacks and whether the various modules are vulnerable to them. -========================= ======== ========= ========= ======== ========= -kind sax etree minidom pulldom xmlrpc -========================= ======== ========= ========= ======== ========= -billion laughs **Yes** **Yes** **Yes** **Yes** **Yes** -quadratic blowup **Yes** **Yes** **Yes** **Yes** **Yes** -external entity expansion **Yes** No (1) No (2) **Yes** No (3) -`DTD`_ retrieval **Yes** No No **Yes** No -decompression bomb No No No No **Yes** -========================= ======== ========= ========= ======== ========= +========================= ============== =============== ============== ============== ============== +kind sax etree minidom pulldom xmlrpc +========================= ============== =============== ============== ============== ============== +billion laughs **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +quadratic blowup **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +external entity expansion **Vulnerable** Safe (1) Safe (2) **Vulnerable** Safe (3) +`DTD`_ retrieval **Vulnerable** Safe Safe **Vulnerable** Safe +decompression bomb Safe Safe Safe Safe **Vulnerable** +========================= ============== =============== ============== ============== ============== 1. :mod:`xml.etree.ElementTree` doesn't expand external entities and raises a :exc:`ParserError` when an entity occurs. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 13 17:35:37 2016 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 13 Oct 2016 21:35:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4Nzg5?= =?utf-8?q?=3A_Update_XML_vulnerability_table_to_use_Safe/Vulnerable_inste?= =?utf-8?q?ad_of?= Message-ID: <20161013213533.15793.16183.8EB88F94@psf.io> https://hg.python.org/cpython/rev/760403522d6b changeset: 104484:760403522d6b branch: 2.7 parent: 104474:bc8a4b121aec user: Guido van Rossum date: Thu Oct 13 14:34:20 2016 -0700 summary: Issue #18789: Update XML vulnerability table to use Safe/Vulnerable instead of No/Yes. (backport to 2.7) files: Doc/library/xml.rst | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -56,15 +56,15 @@ The following table gives an overview of the known attacks and if the various modules are vulnerable to them. -========================= ======== ========= ========= ======== ========= -kind sax etree minidom pulldom xmlrpc -========================= ======== ========= ========= ======== ========= -billion laughs **Yes** **Yes** **Yes** **Yes** **Yes** -quadratic blowup **Yes** **Yes** **Yes** **Yes** **Yes** -external entity expansion **Yes** No (1) No (2) **Yes** No (3) -`DTD`_ retrieval **Yes** No No **Yes** No -decompression bomb No No No No **Yes** -========================= ======== ========= ========= ======== ========= +========================= ============== =============== ============== ============== ============== +kind sax etree minidom pulldom xmlrpc +========================= ============== =============== ============== ============== ============== +billion laughs **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +quadratic blowup **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** +external entity expansion **Vulnerable** Safe (1) Safe (2) **Vulnerable** Safe (3) +`DTD`_ retrieval **Vulnerable** Safe Safe **Vulnerable** Safe +decompression bomb Safe Safe Safe Safe **Vulnerable** +========================= ============== =============== ============== ============== ============== 1. :mod:`xml.etree.ElementTree` doesn't expand external entities and raises a ParserError when an entity occurs. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 01:20:06 2016 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 14 Oct 2016 05:20:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzE4ODQ0?= =?utf-8?q?=3A__Add_more_tests?= Message-ID: <20161014052006.17582.53653.061E2C84@psf.io> https://hg.python.org/cpython/rev/d4e715e725ef changeset: 104485:d4e715e725ef branch: 3.6 parent: 104482:beed43d7dc46 user: Raymond Hettinger date: Fri Oct 14 01:19:38 2016 -0400 summary: Issue #18844: Add more tests files: Lib/test/test_random.py | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -205,6 +205,20 @@ ]: self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data)) + # Test weight focused on a single element of the population + self.assertEqual(choices('abcd', [1, 0, 0, 0]), ['a']) + self.assertEqual(choices('abcd', [0, 1, 0, 0]), ['b']) + self.assertEqual(choices('abcd', [0, 0, 1, 0]), ['c']) + self.assertEqual(choices('abcd', [0, 0, 0, 1]), ['d']) + + # Test consistency with random.choice() for empty population + with self.assertRaises(IndexError): + choices([], k=1) + with self.assertRaises(IndexError): + choices([], weights=[], k=1) + with self.assertRaises(IndexError): + choices([], cum_weights=[], k=5) + def test_gauss(self): # Ensure that the seed() method initializes all the hidden state. In # particular, through 2.2.1 it failed to reset a piece of state used -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 01:20:06 2016 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 14 Oct 2016 05:20:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20161014052006.21187.5010.95C60C84@psf.io> https://hg.python.org/cpython/rev/2dd8689ce678 changeset: 104486:2dd8689ce678 parent: 104483:9513fac97ddd parent: 104485:d4e715e725ef user: Raymond Hettinger date: Fri Oct 14 01:20:00 2016 -0400 summary: merge files: Lib/test/test_random.py | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -205,6 +205,20 @@ ]: self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data)) + # Test weight focused on a single element of the population + self.assertEqual(choices('abcd', [1, 0, 0, 0]), ['a']) + self.assertEqual(choices('abcd', [0, 1, 0, 0]), ['b']) + self.assertEqual(choices('abcd', [0, 0, 1, 0]), ['c']) + self.assertEqual(choices('abcd', [0, 0, 0, 1]), ['d']) + + # Test consistency with random.choice() for empty population + with self.assertRaises(IndexError): + choices([], k=1) + with self.assertRaises(IndexError): + choices([], weights=[], k=1) + with self.assertRaises(IndexError): + choices([], cum_weights=[], k=5) + def test_gauss(self): # Ensure that the seed() method initializes all the hidden state. In # particular, through 2.2.1 it failed to reset a piece of state used -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 02:00:46 2016 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 14 Oct 2016 06:00:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_=5Bmerge_from_3=2E6=5D_Issue28438_-_Fix_the_link_for_pkg?= =?utf-8?q?util=2Eget=5Fdata_doc=2E?= Message-ID: <20161014060044.15189.75431.FB08237A@psf.io> https://hg.python.org/cpython/rev/897fe8fa14b5 changeset: 104489:897fe8fa14b5 parent: 104486:2dd8689ce678 parent: 104488:f2110f41012e user: Senthil Kumaran date: Thu Oct 13 23:00:37 2016 -0700 summary: [merge from 3.6] Issue28438 - Fix the link for pkgutil.get_data doc. Patch contributed by Xiang Zhang. files: Doc/library/pkgutil.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -206,7 +206,8 @@ Get a resource from a package. - This is a wrapper for the :term:`loader` :func:`get_data` API. The + This is a wrapper for the :term:`loader` + :meth:`get_data ` API. The *package* argument should be the name of a package, in standard module format (``foo.bar``). The *resource* argument should be in the form of a relative filename, using ``/`` as the path separator. The parent directory name @@ -222,4 +223,5 @@ data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :term:`loader` - which does not support :func:`get_data`, then ``None`` is returned. + which does not support :meth:`get_data `, + then ``None`` is returned. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 02:00:46 2016 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 14 Oct 2016 06:00:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_=5Bmerge_from_3=2E5=5D_Issue28438_-_Fix_the_link_for_pkgutil?= =?utf-8?q?=2Eget=5Fdata_doc=2E?= Message-ID: <20161014060044.1569.36353.5A8FC56B@psf.io> https://hg.python.org/cpython/rev/f2110f41012e changeset: 104488:f2110f41012e branch: 3.6 parent: 104485:d4e715e725ef parent: 104487:7fb90c4ae643 user: Senthil Kumaran date: Thu Oct 13 22:59:36 2016 -0700 summary: [merge from 3.5] Issue28438 - Fix the link for pkgutil.get_data doc. Patch contributed by Xiang Zhang. files: Doc/library/pkgutil.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -206,7 +206,8 @@ Get a resource from a package. - This is a wrapper for the :term:`loader` :func:`get_data` API. The + This is a wrapper for the :term:`loader` + :meth:`get_data ` API. The *package* argument should be the name of a package, in standard module format (``foo.bar``). The *resource* argument should be in the form of a relative filename, using ``/`` as the path separator. The parent directory name @@ -222,4 +223,5 @@ data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :term:`loader` - which does not support :func:`get_data`, then ``None`` is returned. + which does not support :meth:`get_data `, + then ``None`` is returned. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 02:00:46 2016 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 14 Oct 2016 06:00:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Issue28438_-_F?= =?utf-8?q?ix_the_link_for_pkgutil=2Eget=5Fdata_doc=2E_Patch_contributed_b?= =?utf-8?q?y_Xiang?= Message-ID: <20161014060044.1333.59366.DC674118@psf.io> https://hg.python.org/cpython/rev/7fb90c4ae643 changeset: 104487:7fb90c4ae643 branch: 3.5 parent: 104481:e05c546062a1 user: Senthil Kumaran date: Thu Oct 13 22:58:47 2016 -0700 summary: Issue28438 - Fix the link for pkgutil.get_data doc. Patch contributed by Xiang Zhang. files: Doc/library/pkgutil.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -201,7 +201,8 @@ Get a resource from a package. - This is a wrapper for the :term:`loader` :func:`get_data` API. The + This is a wrapper for the :term:`loader` + :meth:`get_data ` API. The *package* argument should be the name of a package, in standard module format (``foo.bar``). The *resource* argument should be in the form of a relative filename, using ``/`` as the path separator. The parent directory name @@ -217,4 +218,5 @@ data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :term:`loader` - which does not support :func:`get_data`, then ``None`` is returned. + which does not support :meth:`get_data `, + then ``None`` is returned. -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Fri Oct 14 09:55:19 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 14 Oct 2016 14:55:19 +0100 Subject: [Python-checkins] BAD Benchmark Results for Python 2.7 2016-10-14 Message-ID: <43bd8503-cf4a-403f-b63f-694ad7ebc9c9@irsmsx153.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-14 02:47:08 +0000 commit: 760403522d6b previous commit: c29045efd25e revision date: 2016-10-13 21:34:20 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% -2.09% 3.88% 5.40% :-) pybench 0.17% -0.05% 6.02% 4.02% :-( regex_v8 0.68% 0.05% -2.13% 11.01% :-) nbody 0.06% -0.02% 8.00% 1.70% :-) json_dump_v2 0.26% -0.20% 2.65% 8.69% :-| normal_startup 0.57% -0.89% -0.66% 2.38% :-) ssbench 0.17% -0.34% 2.17% 1.41% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/bad-benchmark-results-for-python-2-7-2016-10-14/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Fri Oct 14 09:56:39 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 14 Oct 2016 14:56:39 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-14 Message-ID: Results for project Python default, build date 2016-10-14 02:01:07 +0000 commit: 9513fac97ddd previous commit: 8bb426d386a5 revision date: 2016-10-13 21:32:55 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.24% 2.02% 5.78% 15.13% :-) pybench 0.12% -0.19% 5.26% 4.28% :-( regex_v8 3.69% 0.05% -3.35% 4.58% :-) nbody 0.07% -0.56% 2.79% 4.72% :-( json_dump_v2 0.38% -0.75% -11.30% 17.57% :-) normal_startup 0.92% -0.14% 2.04% 6.77% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-14/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Fri Oct 14 14:54:24 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 18:54:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_wildcard_imports_fr?= =?utf-8?q?om_distutils=2Ecommand=2Esdist?= Message-ID: <20161014185424.15383.44645.8CD5D5B4@psf.io> https://hg.python.org/cpython/rev/b898c11172fe changeset: 104490:b898c11172fe user: Jason R. Coombs date: Fri Oct 14 14:06:28 2016 -0400 summary: Remove wildcard imports from distutils.command.sdist files: Lib/distutils/command/sdist.py | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -4,17 +4,17 @@ import os import sys -from types import * from glob import glob from warnings import warn from distutils.core import Command from distutils import dir_util, dep_util, file_util, archive_util from distutils.text_file import TextFile -from distutils.errors import * from distutils.filelist import FileList from distutils import log from distutils.util import convert_path +from distutils.errors import DistutilsTemplateError, DistutilsOptionError + def show_formats(): """Print all possible values for the 'formats' option (used by -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 14:54:24 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 18:54:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Get_names_for_README_files?= =?utf-8?q?_from_class_attribute=2C_allowing_subclass_to_override=2E?= Message-ID: <20161014185424.17369.46021.8F1E2481@psf.io> https://hg.python.org/cpython/rev/bc22a1df844d changeset: 104493:bc22a1df844d user: Jason R. Coombs date: Fri Oct 14 14:44:11 2016 -0400 summary: Get names for README files from class attribute, allowing subclass to override. files: Lib/distutils/command/sdist.py | 4 +++- 1 files changed, 3 insertions(+), 1 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 @@ -95,6 +95,8 @@ sub_commands = [('check', checking_metadata)] + READMES = 'README', 'README.txt' + def initialize_options(self): # 'template' and 'manifest' are, respectively, the names of # the manifest template and manifest file. @@ -218,7 +220,7 @@ Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ - standards = [('README', 'README.txt'), self.distribution.script_name] + standards = [self.READMES, self.distribution.script_name] for fn in standards: if isinstance(fn, tuple): alts = fn -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 14:54:24 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 18:54:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Extract_methods_from_sdist?= =?utf-8?q?=2Eadd=5Fdefaults=2C_allowing_subclasses_to_override_or?= Message-ID: <20161014185424.1465.69755.668801FD@psf.io> https://hg.python.org/cpython/rev/6d5603e41569 changeset: 104494:6d5603e41569 user: Jason R. Coombs date: Fri Oct 14 14:53:32 2016 -0400 summary: Extract methods from sdist.add_defaults, allowing subclasses to override or inject different behaviors. files: Lib/distutils/command/sdist.py | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 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 @@ -220,6 +220,15 @@ Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ + self._add_defaults_standards() + self._add_defaults_optional() + self._add_defaults_python() + self._add_defaults_data_files() + self._add_defaults_ext() + self._add_defaults_c_libs() + self._add_defaults_scripts() + + def _add_defaults_standards(self): standards = [self.READMES, self.distribution.script_name] for fn in standards: if isinstance(fn, tuple): @@ -240,11 +249,13 @@ else: self.warn("standard file '%s' not found" % fn) + def _add_defaults_optional(self): optional = ['test/test*.py', 'setup.cfg'] for pattern in optional: files = filter(os.path.isfile, glob(pattern)) self.filelist.extend(files) + def _add_defaults_python(self): # build_py is used to get: # - python modules # - files defined in package_data @@ -260,6 +271,7 @@ for filename in filenames: self.filelist.append(os.path.join(src_dir, filename)) + def _add_defaults_data_files(self): # getting distribution.data_files if self.distribution.has_data_files(): for item in self.distribution.data_files: @@ -276,14 +288,17 @@ if os.path.isfile(f): self.filelist.append(f) + def _add_defaults_ext(self): if self.distribution.has_ext_modules(): build_ext = self.get_finalized_command('build_ext') self.filelist.extend(build_ext.get_source_files()) + def _add_defaults_c_libs(self): if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.filelist.extend(build_clib.get_source_files()) + def _add_defaults_scripts(self): if self.distribution.has_scripts(): build_scripts = self.get_finalized_command('build_scripts') self.filelist.extend(build_scripts.get_source_files()) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 14:54:24 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 18:54:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_unused_import_and_r?= =?utf-8?q?eorganize_imports_of_modules=2E?= Message-ID: <20161014185424.15189.24101.5BD09D13@psf.io> https://hg.python.org/cpython/rev/5c3f39fd6437 changeset: 104491:5c3f39fd6437 user: Jason R. Coombs date: Fri Oct 14 14:08:28 2016 -0400 summary: Remove unused import and reorganize imports of modules. files: Lib/distutils/command/sdist.py | 4 +++- 1 files changed, 3 insertions(+), 1 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 @@ -8,7 +8,9 @@ from warnings import warn from distutils.core import Command -from distutils import dir_util, dep_util, file_util, archive_util +from distutils import dir_util +from distutils import file_util +from distutils import archive_util from distutils.text_file import TextFile from distutils.filelist import FileList from distutils import log -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 14:54:24 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 18:54:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Replace_trailing_comments_?= =?utf-8?q?with_block-level_comments?= Message-ID: <20161014185424.32822.71958.66F3197F@psf.io> https://hg.python.org/cpython/rev/50f0ae35df51 changeset: 104492:50f0ae35df51 user: Jason R. Coombs date: Fri Oct 14 14:10:07 2016 -0400 summary: Replace trailing comments with block-level comments files: Lib/distutils/command/sdist.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 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 @@ -261,11 +261,13 @@ # getting distribution.data_files if self.distribution.has_data_files(): for item in self.distribution.data_files: - if isinstance(item, str): # plain file + if isinstance(item, str): + # plain file item = convert_path(item) if os.path.isfile(item): self.filelist.append(item) - else: # a (dirname, filenames) tuple + else: + # a (dirname, filenames) tuple dirname, filenames = item for f in filenames: f = convert_path(f) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 15:39:07 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 19:39:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_case-sensitive_file_co?= =?utf-8?q?mparison_for_detecting/adding_standard_default_files=2E?= Message-ID: <20161014193907.58849.2814.9E0972FA@psf.io> https://hg.python.org/cpython/rev/ed95bb0d7572 changeset: 104495:ed95bb0d7572 user: Jason R. Coombs date: Fri Oct 14 15:39:01 2016 -0400 summary: Add case-sensitive file comparison for detecting/adding standard default files. files: Lib/distutils/command/sdist.py | 22 ++++++++++++++++++++-- Misc/NEWS | 5 +++++ 2 files changed, 25 insertions(+), 2 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 @@ -32,6 +32,24 @@ FancyGetopt(formats).print_help( "List of available source distribution formats:") + +def cs_path_exists(fspath): + """ + Case-sensitive path existence check + + >>> cs_path_exists(__file__) + True + >>> cs_path_exists(__file__.upper()) + False + """ + if not os.path.exists(fspath): + return False + # make absolute so we always have a directory + abspath = os.path.abspath(fspath) + directory, filename = os.path.split(abspath) + return filename in os.listdir(directory) + + class sdist(Command): description = "create a source distribution (tarball, zip file, etc.)" @@ -235,7 +253,7 @@ alts = fn got_it = False for fn in alts: - if os.path.exists(fn): + if cs_path_exists(fn): got_it = True self.filelist.append(fn) break @@ -244,7 +262,7 @@ self.warn("standard file not found: should have one of " + ', '.join(alts)) else: - if os.path.exists(fn): + if cs_path_exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,11 @@ Library ------- +- Distutils.sdist now looks for README and setup.py files with case + sensitivity. This behavior matches that found in Setuptools 6.0 and + later. See `setuptools 100 + `_ for rationale. + - Issue #24452: Make webbrowser support Chrome on Mac OS X. - Issue #20766: Fix references leaked by pdb in the handling of SIGINT -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 15:41:55 2016 From: python-checkins at python.org (jason.coombs) Date: Fri, 14 Oct 2016 19:41:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_cs=5Fpath=5Fexists_a_?= =?utf-8?q?protected=2C_static_method?= Message-ID: <20161014194154.1506.10856.A1288051@psf.io> https://hg.python.org/cpython/rev/db8bb1bd6ac5 changeset: 104496:db8bb1bd6ac5 user: Jason R. Coombs date: Fri Oct 14 15:41:42 2016 -0400 summary: Make cs_path_exists a protected, static method files: Lib/distutils/command/sdist.py | 38 +++++++++++----------- 1 files changed, 19 insertions(+), 19 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 @@ -33,23 +33,6 @@ "List of available source distribution formats:") -def cs_path_exists(fspath): - """ - Case-sensitive path existence check - - >>> cs_path_exists(__file__) - True - >>> cs_path_exists(__file__.upper()) - False - """ - if not os.path.exists(fspath): - return False - # make absolute so we always have a directory - abspath = os.path.abspath(fspath) - directory, filename = os.path.split(abspath) - return filename in os.listdir(directory) - - class sdist(Command): description = "create a source distribution (tarball, zip file, etc.)" @@ -246,6 +229,23 @@ self._add_defaults_c_libs() self._add_defaults_scripts() + @staticmethod + def _cs_path_exists(fspath): + """ + Case-sensitive path existence check + + >>> sdist._cs_path_exists(__file__) + True + >>> sdist._cs_path_exists(__file__.upper()) + False + """ + if not os.path.exists(fspath): + return False + # make absolute so we always have a directory + abspath = os.path.abspath(fspath) + directory, filename = os.path.split(abspath) + return filename in os.listdir(directory) + def _add_defaults_standards(self): standards = [self.READMES, self.distribution.script_name] for fn in standards: @@ -253,7 +253,7 @@ alts = fn got_it = False for fn in alts: - if cs_path_exists(fn): + if self._cs_path_exists(fn): got_it = True self.filelist.append(fn) break @@ -262,7 +262,7 @@ self.warn("standard file not found: should have one of " + ', '.join(alts)) else: - if cs_path_exists(fn): + if self._cs_path_exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:05:08 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:05:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIzMjMx?= =?utf-8?q?=3A_Document_codecs=2Eiterencode=28=29=2C_iterdecode=28=29_shor?= =?utf-8?q?tcomings?= Message-ID: <20161015010508.5346.85142.2EA53EEC@psf.io> https://hg.python.org/cpython/rev/402eba63650c changeset: 104497:402eba63650c branch: 3.5 parent: 104487:7fb90c4ae643 user: Martin Panter date: Sat Oct 15 00:56:47 2016 +0000 summary: Issue #23231: Document codecs.iterencode(), iterdecode() shortcomings files: Doc/library/codecs.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -224,6 +224,10 @@ The *errors* argument (as well as any other keyword argument) is passed through to the incremental encoder. + This function requires that the codec accept text :class:`str` objects + to encode. Therefore it does not support bytes-to-bytes encoders such as + ``base64_codec``. + .. function:: iterdecode(iterator, encoding, errors='strict', **kwargs) @@ -232,6 +236,11 @@ The *errors* argument (as well as any other keyword argument) is passed through to the incremental decoder. + This function requires that the codec accept :class:`bytes` objects + to decode. Therefore it does not support text-to-text encoders such as + ``rot_13``, although ``rot_13`` may be used equivalently with + :func:`iterencode`. + The module also provides the following constants which are useful for reading and writing to platform dependent files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:05:08 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:05:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323231=3A_Merge_codecs_doc_from_3=2E6?= Message-ID: <20161015010508.33023.63162.1369AE0E@psf.io> https://hg.python.org/cpython/rev/1955dcc27332 changeset: 104499:1955dcc27332 parent: 104496:db8bb1bd6ac5 parent: 104498:0837940bcb9f user: Martin Panter date: Sat Oct 15 01:04:36 2016 +0000 summary: Issue #23231: Merge codecs doc from 3.6 files: Doc/library/codecs.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -224,6 +224,10 @@ The *errors* argument (as well as any other keyword argument) is passed through to the incremental encoder. + This function requires that the codec accept text :class:`str` objects + to encode. Therefore it does not support bytes-to-bytes encoders such as + ``base64_codec``. + .. function:: iterdecode(iterator, encoding, errors='strict', **kwargs) @@ -232,6 +236,11 @@ The *errors* argument (as well as any other keyword argument) is passed through to the incremental decoder. + This function requires that the codec accept :class:`bytes` objects + to decode. Therefore it does not support text-to-text encoders such as + ``rot_13``, although ``rot_13`` may be used equivalently with + :func:`iterencode`. + The module also provides the following constants which are useful for reading and writing to platform dependent files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:05:08 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:05:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2323231=3A_Merge_codecs_doc_from_3=2E5_into_3=2E6?= Message-ID: <20161015010508.15637.91701.916AAAC0@psf.io> https://hg.python.org/cpython/rev/0837940bcb9f changeset: 104498:0837940bcb9f branch: 3.6 parent: 104488:f2110f41012e parent: 104497:402eba63650c user: Martin Panter date: Sat Oct 15 01:04:08 2016 +0000 summary: Issue #23231: Merge codecs doc from 3.5 into 3.6 files: Doc/library/codecs.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -224,6 +224,10 @@ The *errors* argument (as well as any other keyword argument) is passed through to the incremental encoder. + This function requires that the codec accept text :class:`str` objects + to encode. Therefore it does not support bytes-to-bytes encoders such as + ``base64_codec``. + .. function:: iterdecode(iterator, encoding, errors='strict', **kwargs) @@ -232,6 +236,11 @@ The *errors* argument (as well as any other keyword argument) is passed through to the incremental decoder. + This function requires that the codec accept :class:`bytes` objects + to decode. Therefore it does not support text-to-text encoders such as + ``rot_13``, although ``rot_13`` may be used equivalently with + :func:`iterencode`. + The module also provides the following constants which are useful for reading and writing to platform dependent files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:45:31 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:45:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3ODAw?= =?utf-8?q?=3A_Document_limitation_and_workaround_for_multiple_RE_repetiti?= =?utf-8?q?ons?= Message-ID: <20161015014531.1717.37500.97A00367@psf.io> https://hg.python.org/cpython/rev/5f7d7e079e39 changeset: 104500:5f7d7e079e39 branch: 3.5 parent: 104497:402eba63650c user: Martin Panter date: Sat Oct 15 01:18:16 2016 +0000 summary: Issue #27800: Document limitation and workaround for multiple RE repetitions files: Doc/library/re.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -79,6 +79,12 @@ expression pattern strings may not contain null bytes, but can specify the null byte using a ``\number`` notation such as ``'\x00'``. +Repetition qualifiers (``*``, ``+``, ``?``, ``{m,n}``, etc) cannot be +directly nested. This avoids ambiguity with the non-greedy modifier suffix +``?``, and with other modifiers in other implementations. To apply a second +repetition to an inner repetition, parentheses may be used. For example, +the expression ``(?:a{6})*`` matches any multiple of six ``'a'`` characters. + The special characters are: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:45:31 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:45:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2327800=3A_Merge_RE_repetition_doc_from_3=2E5_into_3=2E?= =?utf-8?q?6?= Message-ID: <20161015014531.32868.36810.83A52B7E@psf.io> https://hg.python.org/cpython/rev/1f2ca7e4b64e changeset: 104501:1f2ca7e4b64e branch: 3.6 parent: 104498:0837940bcb9f parent: 104500:5f7d7e079e39 user: Martin Panter date: Sat Oct 15 01:39:01 2016 +0000 summary: Issue #27800: Merge RE repetition doc from 3.5 into 3.6 files: Doc/library/re.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -79,6 +79,12 @@ expression pattern strings may not contain null bytes, but can specify the null byte using a ``\number`` notation such as ``'\x00'``. +Repetition qualifiers (``*``, ``+``, ``?``, ``{m,n}``, etc) cannot be +directly nested. This avoids ambiguity with the non-greedy modifier suffix +``?``, and with other modifiers in other implementations. To apply a second +repetition to an inner repetition, parentheses may be used. For example, +the expression ``(?:a{6})*`` matches any multiple of six ``'a'`` characters. + The special characters are: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:45:31 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:45:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327800=3A_Merge_RE_repetition_doc_from_3=2E6?= Message-ID: <20161015014531.32868.52605.DA93ECE6@psf.io> https://hg.python.org/cpython/rev/98456ab88ab0 changeset: 104502:98456ab88ab0 parent: 104499:1955dcc27332 parent: 104501:1f2ca7e4b64e user: Martin Panter date: Sat Oct 15 01:39:21 2016 +0000 summary: Issue #27800: Merge RE repetition doc from 3.6 files: Doc/library/re.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -79,6 +79,12 @@ expression pattern strings may not contain null bytes, but can specify the null byte using a ``\number`` notation such as ``'\x00'``. +Repetition qualifiers (``*``, ``+``, ``?``, ``{m,n}``, etc) cannot be +directly nested. This avoids ambiguity with the non-greedy modifier suffix +``?``, and with other modifiers in other implementations. To apply a second +repetition to an inner repetition, parentheses may be used. For example, +the expression ``(?:a{6})*`` matches any multiple of six ``'a'`` characters. + The special characters are: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 14 21:45:31 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 15 Oct 2016 01:45:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI3ODAw?= =?utf-8?q?=3A_Document_limitation_and_workaround_for_multiple_RE_repetiti?= =?utf-8?q?ons?= Message-ID: <20161015014531.1397.29220.8F440086@psf.io> https://hg.python.org/cpython/rev/94f02193f00f changeset: 104503:94f02193f00f branch: 2.7 parent: 104484:760403522d6b user: Martin Panter date: Sat Oct 15 01:18:16 2016 +0000 summary: Issue #27800: Document limitation and workaround for multiple RE repetitions files: Doc/library/re.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -70,6 +70,12 @@ expression pattern strings may not contain null bytes, but can specify the null byte using the ``\number`` notation, e.g., ``'\x00'``. +Repetition qualifiers (``*``, ``+``, ``?``, ``{m,n}``, etc) cannot be +directly nested. This avoids ambiguity with the non-greedy modifier suffix +``?``, and with other modifiers in other implementations. To apply a second +repetition to an inner repetition, parentheses may be used. For example, +the expression ``(?:a{6})*`` matches any multiple of six ``'a'`` characters. + The special characters are: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 15 02:41:17 2016 From: python-checkins at python.org (inada.naoki) Date: Sat, 15 Oct 2016 06:41:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328428=3A_Rename_=5Ffutures_module_to_=5Fasyncio?= =?utf-8?b?LiAobWVyZ2UgZnJvbSAzLjYp?= Message-ID: <20161015064117.12020.89586.94B994D5@psf.io> https://hg.python.org/cpython/rev/c2f3b7c56dff changeset: 104505:c2f3b7c56dff parent: 104502:98456ab88ab0 parent: 104504:9d06fdedae2b user: INADA Naoki date: Sat Oct 15 15:41:05 2016 +0900 summary: Issue #28428: Rename _futures module to _asyncio. (merge from 3.6) It will have more speedup functions or classes other than asyncio.Future. files: Lib/asyncio/futures.py | 6 +- Modules/Setup.dist | 2 +- Modules/_asynciomodule.c | 1034 ++++++++++++++++ Modules/_futuresmodule.c | 1034 ---------------- PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 6 +- setup.py | 4 +- 7 files changed, 1044 insertions(+), 1044 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -432,18 +432,18 @@ try: - import _futures + import _asyncio except ImportError: pass else: - _futures._init_module( + _asyncio._init_module( traceback.extract_stack, events.get_event_loop, _future_repr_info, InvalidStateError, CancelledError) - Future = _futures.Future + Future = _asyncio.Future def _chain_future(source, destination): diff --git a/Modules/Setup.dist b/Modules/Setup.dist --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -181,7 +181,7 @@ #_datetime _datetimemodule.c # datetime accelerator #_bisect _bisectmodule.c # Bisection algorithms #_heapq _heapqmodule.c # Heap queue algorithm -#_futures _futuresmodule.c # Fast asyncio Future +#_asyncio _asynciomodule.c # Fast asyncio Future #unicodedata unicodedata.c # static Unicode character database diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c new file mode 100644 --- /dev/null +++ b/Modules/_asynciomodule.c @@ -0,0 +1,1034 @@ +#include "Python.h" +#include "structmember.h" + + +/* identifiers used from some functions */ +_Py_IDENTIFIER(call_soon); + + +/* State of the _asyncio module */ +static int _asynciomod_ready; +static PyObject *traceback_extract_stack; +static PyObject *asyncio_get_event_loop; +static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_InvalidStateError; +static PyObject *asyncio_CancelledError; + + +/* Get FutureIter from Future */ +static PyObject* new_future_iter(PyObject *fut); + + +/* make sure module state is initialized and ready to be used. */ +static int +_AsyncioMod_EnsureState(void) +{ + if (!_asynciomod_ready) { + PyErr_SetString(PyExc_RuntimeError, + "_asyncio module wasn't properly initialized"); + return -1; + } + return 0; +} + + +typedef enum { + STATE_PENDING, + STATE_CANCELLED, + STATE_FINISHED +} fut_state; + + +typedef struct { + PyObject_HEAD + PyObject *fut_loop; + PyObject *fut_callbacks; + PyObject *fut_exception; + PyObject *fut_result; + PyObject *fut_source_tb; + fut_state fut_state; + int fut_log_tb; + int fut_blocking; + PyObject *dict; + PyObject *fut_weakreflist; +} FutureObj; + + +static int +_schedule_callbacks(FutureObj *fut) +{ + Py_ssize_t len; + PyObject* iters; + int i; + + if (fut->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); + return -1; + } + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return 0; + } + + iters = PyList_GetSlice(fut->fut_callbacks, 0, len); + if (iters == NULL) { + return -1; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { + Py_DECREF(iters); + return -1; + } + + for (i = 0; i < len; i++) { + PyObject *handle = NULL; + PyObject *cb = PyList_GET_ITEM(iters, i); + + handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); + + if (handle == NULL) { + Py_DECREF(iters); + return -1; + } + else { + Py_DECREF(handle); + } + } + + Py_DECREF(iters); + return 0; +} + +static int +FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"loop", NULL}; + PyObject *loop = NULL; + PyObject *res = NULL; + _Py_IDENTIFIER(get_debug); + + if (_AsyncioMod_EnsureState()) { + return -1; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { + return -1; + } + if (loop == NULL || loop == Py_None) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return -1; + } + } + else { + Py_INCREF(loop); + } + Py_CLEAR(fut->fut_loop); + fut->fut_loop = loop; + + res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); + if (res == NULL) { + return -1; + } + if (PyObject_IsTrue(res)) { + Py_CLEAR(res); + fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); + if (fut->fut_source_tb == NULL) { + return -1; + } + } + else { + Py_CLEAR(res); + } + + fut->fut_callbacks = PyList_New(0); + if (fut->fut_callbacks == NULL) { + return -1; + } + return 0; +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +PyDoc_STRVAR(pydoc_result, + "Return the result this future represents.\n" + "\n" + "If the future has been cancelled, raises CancelledError. If the\n" + "future's result isn't yet available, raises InvalidStateError. If\n" + "the future is done and has an exception set, this exception is raised." +); + +static PyObject * +FutureObj_result(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + PyObject *type = NULL; + type = PyExceptionInstance_Class(fut->fut_exception); + PyErr_SetObject(type, fut->fut_exception); + return NULL; + } + + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +PyDoc_STRVAR(pydoc_exception, + "Return the exception that was set on this future.\n" + "\n" + "The exception (or None if no exception was set) is returned only if\n" + "the future is done. If the future has been cancelled, raises\n" + "CancelledError. If the future isn't done yet, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_exception(FutureObj *fut, PyObject *arg) +{ + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (fut->fut_exception != NULL) { + fut->fut_log_tb = 0; + Py_INCREF(fut->fut_exception); + return fut->fut_exception; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_result, + "Mark the future done and set its result.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_result(FutureObj *fut, PyObject *res) +{ + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + Py_INCREF(res); + fut->fut_result = res; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_exception, + "Mark the future done and set an exception.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_exception(FutureObj *fut, PyObject *exc) +{ + PyObject *exc_val = NULL; + + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + if (PyExceptionClass_Check(exc)) { + exc_val = PyObject_CallObject(exc, NULL); + if (exc_val == NULL) { + return NULL; + } + } + else { + exc_val = exc; + Py_INCREF(exc_val); + } + if (!PyExceptionInstance_Check(exc_val)) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, "invalid exception object"); + return NULL; + } + if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, + "StopIteration interacts badly with generators " + "and cannot be raised into a Future"); + return NULL; + } + + fut->fut_exception = exc_val; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + fut->fut_log_tb = 1; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_add_done_callback, + "Add a callback to be run when the future becomes done.\n" + "\n" + "The callback is called with a single argument - the future object. If\n" + "the future is already done when this is called, the callback is\n" + "scheduled with call_soon."; +); + +static PyObject * +FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + PyObject *handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); + + if (handle == NULL) { + return NULL; + } + else { + Py_DECREF(handle); + } + } + else { + int err = PyList_Append(fut->fut_callbacks, arg); + if (err != 0) { + return NULL; + } + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_remove_done_callback, + "Remove all instances of a callback from the \"call when done\" list.\n" + "\n" + "Returns the number of callbacks removed." +); + +static PyObject * +FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +{ + PyObject *newlist; + Py_ssize_t len, i, j=0; + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return PyLong_FromSsize_t(0); + } + + newlist = PyList_New(len); + if (newlist == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + int ret; + PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + + if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + goto fail; + } + if (ret == 0) { + Py_INCREF(item); + PyList_SET_ITEM(newlist, j, item); + j++; + } + } + + if (PyList_SetSlice(newlist, j, len, NULL) < 0) { + goto fail; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + goto fail; + } + Py_DECREF(newlist); + return PyLong_FromSsize_t(len - j); + +fail: + Py_DECREF(newlist); + return NULL; +} + +PyDoc_STRVAR(pydoc_cancel, + "Cancel the future and schedule callbacks.\n" + "\n" + "If the future is already done or cancelled, return False. Otherwise,\n" + "change the future's state to cancelled, schedule the callbacks and\n" + "return True." +); + +static PyObject * +FutureObj_cancel(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); + +static PyObject * +FutureObj_cancelled(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(pydoc_done, + "Return True if the future is done.\n" + "\n" + "Done means either that a result / exception are available, or that the\n" + "future was cancelled." +); + +static PyObject * +FutureObj_done(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_PENDING) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject * +FutureObj_get_blocking(FutureObj *fut) +{ + if (fut->fut_blocking) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static int +FutureObj_set_blocking(FutureObj *fut, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; + } + fut->fut_blocking = is_true; + return 0; +} + +static PyObject * +FutureObj_get_log_traceback(FutureObj *fut) +{ + if (fut->fut_log_tb) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +FutureObj_get_loop(FutureObj *fut) +{ + if (fut->fut_loop == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_loop); + return fut->fut_loop; +} + +static PyObject * +FutureObj_get_callbacks(FutureObj *fut) +{ + if (fut->fut_callbacks == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_callbacks); + return fut->fut_callbacks; +} + +static PyObject * +FutureObj_get_result(FutureObj *fut) +{ + if (fut->fut_result == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +static PyObject * +FutureObj_get_exception(FutureObj *fut) +{ + if (fut->fut_exception == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_exception); + return fut->fut_exception; +} + +static PyObject * +FutureObj_get_source_traceback(FutureObj *fut) +{ + if (fut->fut_source_tb == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_source_tb); + return fut->fut_source_tb; +} + +static PyObject * +FutureObj_get_state(FutureObj *fut) +{ + _Py_IDENTIFIER(PENDING); + _Py_IDENTIFIER(CANCELLED); + _Py_IDENTIFIER(FINISHED); + PyObject *ret = NULL; + + switch (fut->fut_state) { + case STATE_PENDING: + ret = _PyUnicode_FromId(&PyId_PENDING); + break; + case STATE_CANCELLED: + ret = _PyUnicode_FromId(&PyId_CANCELLED); + break; + case STATE_FINISHED: + ret = _PyUnicode_FromId(&PyId_FINISHED); + break; + default: + assert (0); + } + Py_INCREF(ret); + return ret; +} + +static PyObject* +FutureObj__repr_info(FutureObj *fut) +{ + if (asyncio_repr_info_func == NULL) { + return PyList_New(0); + } + return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); +} + +static PyObject * +FutureObj_repr(FutureObj *fut) +{ + _Py_IDENTIFIER(_repr_info); + + PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed + if (_repr_info == NULL) { + return NULL; + } + + PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, + NULL); + if (rinfo == NULL) { + return NULL; + } + + PyObject *sp = PyUnicode_FromString(" "); + if (sp == NULL) { + Py_DECREF(rinfo); + return NULL; + } + + PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); + Py_DECREF(sp); + Py_DECREF(rinfo); + if (rinfo_s == NULL) { + return NULL; + } + + PyObject *rstr = NULL; + PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), + "__name__"); + if (type_name != NULL) { + rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); + Py_DECREF(type_name); + } + Py_DECREF(rinfo_s); + return rstr; +} + +static void +FutureObj_finalize(FutureObj *fut) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(exception); + _Py_IDENTIFIER(future); + _Py_IDENTIFIER(source_traceback); + + if (!fut->fut_log_tb) { + return; + } + assert(fut->fut_exception != NULL); + fut->fut_log_tb = 0;; + + PyObject *error_type, *error_value, *error_traceback; + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyObject *context = NULL; + PyObject *type_name = NULL; + PyObject *message = NULL; + PyObject *func = NULL; + PyObject *res = NULL; + + context = PyDict_New(); + if (context == NULL) { + goto finally; + } + + type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); + if (type_name == NULL) { + goto finally; + } + + message = PyUnicode_FromFormat( + "%S exception was never retrieved", type_name); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || + _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { + goto finally; + } + if (fut->fut_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + fut->fut_source_tb) < 0) { + goto finally; + } + } + + func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(type_name); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + + +static PyAsyncMethods FutureType_as_async = { + (unaryfunc)new_future_iter, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef FutureType_methods[] = { + {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, + {"add_done_callback", + (PyCFunction)FutureObj_add_done_callback, + METH_O, pydoc_add_done_callback}, + {"remove_done_callback", + (PyCFunction)FutureObj_remove_done_callback, + METH_O, pydoc_remove_done_callback}, + {"set_result", + (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, + {"set_exception", + (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, + {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, + {"cancelled", + (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, + {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, + {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, + {"exception", + (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef FutureType_getsetlist[] = { + {"_state", (getter)FutureObj_get_state, NULL, NULL}, + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, + (setter)FutureObj_set_blocking, NULL}, + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, + {"_result", (getter)FutureObj_get_result, NULL, NULL}, + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static void FutureObj_dealloc(PyObject *self); + +static PyTypeObject FutureType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.Future", + sizeof(FutureObj), /* tp_basicsize */ + .tp_dealloc = FutureObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = "Fast asyncio.Future implementation.", + .tp_traverse = (traverseproc)FutureObj_traverse, + .tp_clear = (inquiry)FutureObj_clear, + .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), + .tp_iter = (getiterfunc)new_future_iter, + .tp_methods = FutureType_methods, + .tp_getset = FutureType_getsetlist, + .tp_dictoffset = offsetof(FutureObj, dict), + .tp_init = (initproc)FutureObj_init, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)FutureObj_finalize, +}; + +static void +FutureObj_dealloc(PyObject *self) +{ + FutureObj *fut = (FutureObj *)self; + + if (Py_TYPE(fut) == &FutureType) { + /* When fut is subclass of Future, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (fut->fut_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + FutureObj_clear(fut); + Py_TYPE(fut)->tp_free(fut); +} + + +/*********************** Future Iterator **************************/ + +typedef struct { + PyObject_HEAD + FutureObj *future; +} futureiterobject; + +static void +FutureIter_dealloc(futureiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->future); + PyObject_GC_Del(it); +} + +static PyObject * +FutureIter_iternext(futureiterobject *it) +{ + PyObject *res; + FutureObj *fut = it->future; + + if (fut == NULL) { + return NULL; + } + + if (fut->fut_state == STATE_PENDING) { + if (!fut->fut_blocking) { + fut->fut_blocking = 1; + Py_INCREF(fut); + return (PyObject *)fut; + } + PyErr_Format(PyExc_AssertionError, + "yield from wasn't used with future"); + return NULL; + } + + res = FutureObj_result(fut, NULL); + if (res != NULL) { + // normal result + PyErr_SetObject(PyExc_StopIteration, res); + Py_DECREF(res); + } + + it->future = NULL; + Py_DECREF(fut); + return NULL; +} + +static PyObject * +FutureIter_send(futureiterobject *self, PyObject *arg) +{ + if (arg != Py_None) { + PyErr_Format(PyExc_TypeError, + "can't send non-None value to a FutureIter"); + return NULL; + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_throw(futureiterobject *self, PyObject *args) +{ + PyObject *type=NULL, *val=NULL, *tb=NULL; + if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) + return NULL; + + if (val == Py_None) { + val = NULL; + } + if (tb == Py_None) { + tb = NULL; + } + + Py_CLEAR(self->future); + + if (tb != NULL) { + PyErr_Restore(type, val, tb); + } + else if (val != NULL) { + PyErr_SetObject(type, val); + } + else { + if (PyExceptionClass_Check(type)) { + val = PyObject_CallObject(type, NULL); + } + else { + val = type; + assert (PyExceptionInstance_Check(val)); + type = (PyObject*)Py_TYPE(val); + assert (PyExceptionClass_Check(type)); + } + PyErr_SetObject(type, val); + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_close(futureiterobject *self, PyObject *arg) +{ + Py_CLEAR(self->future); + Py_RETURN_NONE; +} + +static int +FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->future); + return 0; +} + +static PyMethodDef FutureIter_methods[] = { + {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, + {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, + {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, + {NULL, NULL} /* Sentinel */ +}; + +static PyTypeObject FutureIterType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.FutureIter", + sizeof(futureiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)FutureIter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 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 */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)FutureIter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)FutureIter_iternext, /* tp_iternext */ + FutureIter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +static PyObject * +new_future_iter(PyObject *fut) +{ + futureiterobject *it; + + if (!PyObject_TypeCheck(fut, &FutureType)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(futureiterobject, &FutureIterType); + if (it == NULL) { + return NULL; + } + Py_INCREF(fut); + it->future = (FutureObj*)fut; + PyObject_GC_Track(it); + return (PyObject*)it; +} + +/*********************** Module **************************/ + +PyDoc_STRVAR(module_doc, "asyncio speedups.\n"); + +PyObject * +_init_module(PyObject *self, PyObject *args) +{ + PyObject *extract_stack; + PyObject *get_event_loop; + PyObject *repr_info_func; + PyObject *invalidStateError; + PyObject *cancelledError; + + if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, + &extract_stack, + &get_event_loop, + &repr_info_func, + &invalidStateError, + &cancelledError)) { + return NULL; + } + + Py_INCREF(extract_stack); + Py_XSETREF(traceback_extract_stack, extract_stack); + + Py_INCREF(get_event_loop); + Py_XSETREF(asyncio_get_event_loop, get_event_loop); + + Py_INCREF(repr_info_func); + Py_XSETREF(asyncio_repr_info_func, repr_info_func); + + Py_INCREF(invalidStateError); + Py_XSETREF(asyncio_InvalidStateError, invalidStateError); + + Py_INCREF(cancelledError); + Py_XSETREF(asyncio_CancelledError, cancelledError); + + _asynciomod_ready = 1; + + Py_RETURN_NONE; +} + + +static struct PyMethodDef asynciomod_methods[] = { + {"_init_module", _init_module, METH_VARARGS, NULL}, + {NULL, NULL} +}; + + +static struct PyModuleDef _asynciomodule = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_asyncio", /* m_name */ + module_doc, /* m_doc */ + -1, /* m_size */ + asynciomod_methods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + + +PyMODINIT_FUNC +PyInit__asyncio(void) +{ + if (PyType_Ready(&FutureType) < 0) { + return NULL; + } + if (PyType_Ready(&FutureIterType) < 0) { + return NULL; + } + + PyObject *m = PyModule_Create(&_asynciomodule); + if (m == NULL) { + return NULL; + } + + Py_INCREF(&FutureType); + if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { + Py_DECREF(&FutureType); + return NULL; + } + + return m; +} diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c deleted file mode 100644 --- a/Modules/_futuresmodule.c +++ /dev/null @@ -1,1034 +0,0 @@ -#include "Python.h" -#include "structmember.h" - - -/* identifiers used from some functions */ -_Py_IDENTIFIER(call_soon); - - -/* State of the _futures module */ -static int _futuremod_ready; -static PyObject *traceback_extract_stack; -static PyObject *asyncio_get_event_loop; -static PyObject *asyncio_repr_info_func; -static PyObject *asyncio_InvalidStateError; -static PyObject *asyncio_CancelledError; - - -/* Get FutureIter from Future */ -static PyObject* new_future_iter(PyObject *fut); - - -/* make sure module state is initialized and ready to be used. */ -static int -_FuturesMod_EnsureState(void) -{ - if (!_futuremod_ready) { - PyErr_SetString(PyExc_RuntimeError, - "_futures module wasn't properly initialized"); - return -1; - } - return 0; -} - - -typedef enum { - STATE_PENDING, - STATE_CANCELLED, - STATE_FINISHED -} fut_state; - - -typedef struct { - PyObject_HEAD - PyObject *fut_loop; - PyObject *fut_callbacks; - PyObject *fut_exception; - PyObject *fut_result; - PyObject *fut_source_tb; - fut_state fut_state; - int fut_log_tb; - int fut_blocking; - PyObject *dict; - PyObject *fut_weakreflist; -} FutureObj; - - -static int -_schedule_callbacks(FutureObj *fut) -{ - Py_ssize_t len; - PyObject* iters; - int i; - - if (fut->fut_callbacks == NULL) { - PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); - return -1; - } - - len = PyList_GET_SIZE(fut->fut_callbacks); - if (len == 0) { - return 0; - } - - iters = PyList_GetSlice(fut->fut_callbacks, 0, len); - if (iters == NULL) { - return -1; - } - if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { - Py_DECREF(iters); - return -1; - } - - for (i = 0; i < len; i++) { - PyObject *handle = NULL; - PyObject *cb = PyList_GET_ITEM(iters, i); - - handle = _PyObject_CallMethodId( - fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); - - if (handle == NULL) { - Py_DECREF(iters); - return -1; - } - else { - Py_DECREF(handle); - } - } - - Py_DECREF(iters); - return 0; -} - -static int -FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"loop", NULL}; - PyObject *loop = NULL; - PyObject *res = NULL; - _Py_IDENTIFIER(get_debug); - - if (_FuturesMod_EnsureState()) { - return -1; - } - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { - return -1; - } - if (loop == NULL || loop == Py_None) { - loop = PyObject_CallObject(asyncio_get_event_loop, NULL); - if (loop == NULL) { - return -1; - } - } - else { - Py_INCREF(loop); - } - Py_CLEAR(fut->fut_loop); - fut->fut_loop = loop; - - res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); - if (res == NULL) { - return -1; - } - if (PyObject_IsTrue(res)) { - Py_CLEAR(res); - fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); - if (fut->fut_source_tb == NULL) { - return -1; - } - } - else { - Py_CLEAR(res); - } - - fut->fut_callbacks = PyList_New(0); - if (fut->fut_callbacks == NULL) { - return -1; - } - return 0; -} - -static int -FutureObj_clear(FutureObj *fut) -{ - Py_CLEAR(fut->fut_loop); - Py_CLEAR(fut->fut_callbacks); - Py_CLEAR(fut->fut_result); - Py_CLEAR(fut->fut_exception); - Py_CLEAR(fut->fut_source_tb); - Py_CLEAR(fut->dict); - return 0; -} - -static int -FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) -{ - Py_VISIT(fut->fut_loop); - Py_VISIT(fut->fut_callbacks); - Py_VISIT(fut->fut_result); - Py_VISIT(fut->fut_exception); - Py_VISIT(fut->fut_source_tb); - Py_VISIT(fut->dict); - return 0; -} - -PyDoc_STRVAR(pydoc_result, - "Return the result this future represents.\n" - "\n" - "If the future has been cancelled, raises CancelledError. If the\n" - "future's result isn't yet available, raises InvalidStateError. If\n" - "the future is done and has an exception set, this exception is raised." -); - -static PyObject * -FutureObj_result(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - fut->fut_log_tb = 0; - if (fut->fut_exception != NULL) { - PyObject *type = NULL; - type = PyExceptionInstance_Class(fut->fut_exception); - PyErr_SetObject(type, fut->fut_exception); - return NULL; - } - - Py_INCREF(fut->fut_result); - return fut->fut_result; -} - -PyDoc_STRVAR(pydoc_exception, - "Return the exception that was set on this future.\n" - "\n" - "The exception (or None if no exception was set) is returned only if\n" - "the future is done. If the future has been cancelled, raises\n" - "CancelledError. If the future isn't done yet, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_exception(FutureObj *fut, PyObject *arg) -{ - if (_FuturesMod_EnsureState()) { - return NULL; - } - - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - if (fut->fut_exception != NULL) { - fut->fut_log_tb = 0; - Py_INCREF(fut->fut_exception); - return fut->fut_exception; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_set_result, - "Mark the future done and set its result.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_set_result(FutureObj *fut, PyObject *res) -{ - if (_FuturesMod_EnsureState()) { - return NULL; - } - - if (fut->fut_state != STATE_PENDING) { - PyErr_SetString(asyncio_InvalidStateError, "invalid state"); - return NULL; - } - - Py_INCREF(res); - fut->fut_result = res; - fut->fut_state = STATE_FINISHED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_set_exception, - "Mark the future done and set an exception.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_set_exception(FutureObj *fut, PyObject *exc) -{ - PyObject *exc_val = NULL; - - if (_FuturesMod_EnsureState()) { - return NULL; - } - - if (fut->fut_state != STATE_PENDING) { - PyErr_SetString(asyncio_InvalidStateError, "invalid state"); - return NULL; - } - - if (PyExceptionClass_Check(exc)) { - exc_val = PyObject_CallObject(exc, NULL); - if (exc_val == NULL) { - return NULL; - } - } - else { - exc_val = exc; - Py_INCREF(exc_val); - } - if (!PyExceptionInstance_Check(exc_val)) { - Py_DECREF(exc_val); - PyErr_SetString(PyExc_TypeError, "invalid exception object"); - return NULL; - } - if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { - Py_DECREF(exc_val); - PyErr_SetString(PyExc_TypeError, - "StopIteration interacts badly with generators " - "and cannot be raised into a Future"); - return NULL; - } - - fut->fut_exception = exc_val; - fut->fut_state = STATE_FINISHED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - - fut->fut_log_tb = 1; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_add_done_callback, - "Add a callback to be run when the future becomes done.\n" - "\n" - "The callback is called with a single argument - the future object. If\n" - "the future is already done when this is called, the callback is\n" - "scheduled with call_soon."; -); - -static PyObject * -FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state != STATE_PENDING) { - PyObject *handle = _PyObject_CallMethodId( - fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); - - if (handle == NULL) { - return NULL; - } - else { - Py_DECREF(handle); - } - } - else { - int err = PyList_Append(fut->fut_callbacks, arg); - if (err != 0) { - return NULL; - } - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_remove_done_callback, - "Remove all instances of a callback from the \"call when done\" list.\n" - "\n" - "Returns the number of callbacks removed." -); - -static PyObject * -FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) -{ - PyObject *newlist; - Py_ssize_t len, i, j=0; - - len = PyList_GET_SIZE(fut->fut_callbacks); - if (len == 0) { - return PyLong_FromSsize_t(0); - } - - newlist = PyList_New(len); - if (newlist == NULL) { - return NULL; - } - - for (i = 0; i < len; i++) { - int ret; - PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); - - if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { - goto fail; - } - if (ret == 0) { - Py_INCREF(item); - PyList_SET_ITEM(newlist, j, item); - j++; - } - } - - if (PyList_SetSlice(newlist, j, len, NULL) < 0) { - goto fail; - } - if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { - goto fail; - } - Py_DECREF(newlist); - return PyLong_FromSsize_t(len - j); - -fail: - Py_DECREF(newlist); - return NULL; -} - -PyDoc_STRVAR(pydoc_cancel, - "Cancel the future and schedule callbacks.\n" - "\n" - "If the future is already done or cancelled, return False. Otherwise,\n" - "change the future's state to cancelled, schedule the callbacks and\n" - "return True." -); - -static PyObject * -FutureObj_cancel(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state != STATE_PENDING) { - Py_RETURN_FALSE; - } - fut->fut_state = STATE_CANCELLED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - - Py_RETURN_TRUE; -} - -PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); - -static PyObject * -FutureObj_cancelled(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -PyDoc_STRVAR(pydoc_done, - "Return True if the future is done.\n" - "\n" - "Done means either that a result / exception are available, or that the\n" - "future was cancelled." -); - -static PyObject * -FutureObj_done(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_PENDING) { - Py_RETURN_FALSE; - } - else { - Py_RETURN_TRUE; - } -} - -static PyObject * -FutureObj_get_blocking(FutureObj *fut) -{ - if (fut->fut_blocking) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -static int -FutureObj_set_blocking(FutureObj *fut, PyObject *val) -{ - int is_true = PyObject_IsTrue(val); - if (is_true < 0) { - return -1; - } - fut->fut_blocking = is_true; - return 0; -} - -static PyObject * -FutureObj_get_log_traceback(FutureObj *fut) -{ - if (fut->fut_log_tb) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -static PyObject * -FutureObj_get_loop(FutureObj *fut) -{ - if (fut->fut_loop == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_loop); - return fut->fut_loop; -} - -static PyObject * -FutureObj_get_callbacks(FutureObj *fut) -{ - if (fut->fut_callbacks == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_callbacks); - return fut->fut_callbacks; -} - -static PyObject * -FutureObj_get_result(FutureObj *fut) -{ - if (fut->fut_result == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_result); - return fut->fut_result; -} - -static PyObject * -FutureObj_get_exception(FutureObj *fut) -{ - if (fut->fut_exception == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_exception); - return fut->fut_exception; -} - -static PyObject * -FutureObj_get_source_traceback(FutureObj *fut) -{ - if (fut->fut_source_tb == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_source_tb); - return fut->fut_source_tb; -} - -static PyObject * -FutureObj_get_state(FutureObj *fut) -{ - _Py_IDENTIFIER(PENDING); - _Py_IDENTIFIER(CANCELLED); - _Py_IDENTIFIER(FINISHED); - PyObject *ret = NULL; - - switch (fut->fut_state) { - case STATE_PENDING: - ret = _PyUnicode_FromId(&PyId_PENDING); - break; - case STATE_CANCELLED: - ret = _PyUnicode_FromId(&PyId_CANCELLED); - break; - case STATE_FINISHED: - ret = _PyUnicode_FromId(&PyId_FINISHED); - break; - default: - assert (0); - } - Py_INCREF(ret); - return ret; -} - -static PyObject* -FutureObj__repr_info(FutureObj *fut) -{ - if (asyncio_repr_info_func == NULL) { - return PyList_New(0); - } - return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); -} - -static PyObject * -FutureObj_repr(FutureObj *fut) -{ - _Py_IDENTIFIER(_repr_info); - - PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed - if (_repr_info == NULL) { - return NULL; - } - - PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, - NULL); - if (rinfo == NULL) { - return NULL; - } - - PyObject *sp = PyUnicode_FromString(" "); - if (sp == NULL) { - Py_DECREF(rinfo); - return NULL; - } - - PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); - Py_DECREF(sp); - Py_DECREF(rinfo); - if (rinfo_s == NULL) { - return NULL; - } - - PyObject *rstr = NULL; - PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), - "__name__"); - if (type_name != NULL) { - rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); - Py_DECREF(type_name); - } - Py_DECREF(rinfo_s); - return rstr; -} - -static void -FutureObj_finalize(FutureObj *fut) -{ - _Py_IDENTIFIER(call_exception_handler); - _Py_IDENTIFIER(message); - _Py_IDENTIFIER(exception); - _Py_IDENTIFIER(future); - _Py_IDENTIFIER(source_traceback); - - if (!fut->fut_log_tb) { - return; - } - assert(fut->fut_exception != NULL); - fut->fut_log_tb = 0;; - - PyObject *error_type, *error_value, *error_traceback; - /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - PyObject *context = NULL; - PyObject *type_name = NULL; - PyObject *message = NULL; - PyObject *func = NULL; - PyObject *res = NULL; - - context = PyDict_New(); - if (context == NULL) { - goto finally; - } - - type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); - if (type_name == NULL) { - goto finally; - } - - message = PyUnicode_FromFormat( - "%S exception was never retrieved", type_name); - if (message == NULL) { - goto finally; - } - - if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || - _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || - _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { - goto finally; - } - if (fut->fut_source_tb != NULL) { - if (_PyDict_SetItemId(context, &PyId_source_traceback, - fut->fut_source_tb) < 0) { - goto finally; - } - } - - func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); - if (func != NULL) { - res = _PyObject_CallArg1(func, context); - if (res == NULL) { - PyErr_WriteUnraisable(func); - } - } - -finally: - Py_CLEAR(context); - Py_CLEAR(type_name); - Py_CLEAR(message); - Py_CLEAR(func); - Py_CLEAR(res); - - /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); -} - - -static PyAsyncMethods FutureType_as_async = { - (unaryfunc)new_future_iter, /* am_await */ - 0, /* am_aiter */ - 0 /* am_anext */ -}; - -static PyMethodDef FutureType_methods[] = { - {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, - {"add_done_callback", - (PyCFunction)FutureObj_add_done_callback, - METH_O, pydoc_add_done_callback}, - {"remove_done_callback", - (PyCFunction)FutureObj_remove_done_callback, - METH_O, pydoc_remove_done_callback}, - {"set_result", - (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, - {"set_exception", - (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, - {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, - {"cancelled", - (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, - {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, - {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, - {"exception", - (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, - {NULL, NULL} /* Sentinel */ -}; - -static PyGetSetDef FutureType_getsetlist[] = { - {"_state", (getter)FutureObj_get_state, NULL, NULL}, - {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, - (setter)FutureObj_set_blocking, NULL}, - {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, - {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, - {"_result", (getter)FutureObj_get_result, NULL, NULL}, - {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, - {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, - {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, - {NULL} /* Sentinel */ -}; - -static void FutureObj_dealloc(PyObject *self); - -static PyTypeObject FutureType = { - PyVarObject_HEAD_INIT(0, 0) - "_futures.Future", - sizeof(FutureObj), /* tp_basicsize */ - .tp_dealloc = FutureObj_dealloc, - .tp_as_async = &FutureType_as_async, - .tp_repr = (reprfunc)FutureObj_repr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_FINALIZE, - .tp_doc = "Fast asyncio.Future implementation.", - .tp_traverse = (traverseproc)FutureObj_traverse, - .tp_clear = (inquiry)FutureObj_clear, - .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), - .tp_iter = (getiterfunc)new_future_iter, - .tp_methods = FutureType_methods, - .tp_getset = FutureType_getsetlist, - .tp_dictoffset = offsetof(FutureObj, dict), - .tp_init = (initproc)FutureObj_init, - .tp_new = PyType_GenericNew, - .tp_finalize = (destructor)FutureObj_finalize, -}; - -static void -FutureObj_dealloc(PyObject *self) -{ - FutureObj *fut = (FutureObj *)self; - - if (Py_TYPE(fut) == &FutureType) { - /* When fut is subclass of Future, finalizer is called from - * subtype_dealloc. - */ - if (PyObject_CallFinalizerFromDealloc(self) < 0) { - // resurrected. - return; - } - } - - if (fut->fut_weakreflist != NULL) { - PyObject_ClearWeakRefs(self); - } - - FutureObj_clear(fut); - Py_TYPE(fut)->tp_free(fut); -} - - -/*********************** Future Iterator **************************/ - -typedef struct { - PyObject_HEAD - FutureObj *future; -} futureiterobject; - -static void -FutureIter_dealloc(futureiterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->future); - PyObject_GC_Del(it); -} - -static PyObject * -FutureIter_iternext(futureiterobject *it) -{ - PyObject *res; - FutureObj *fut = it->future; - - if (fut == NULL) { - return NULL; - } - - if (fut->fut_state == STATE_PENDING) { - if (!fut->fut_blocking) { - fut->fut_blocking = 1; - Py_INCREF(fut); - return (PyObject *)fut; - } - PyErr_Format(PyExc_AssertionError, - "yield from wasn't used with future"); - return NULL; - } - - res = FutureObj_result(fut, NULL); - if (res != NULL) { - // normal result - PyErr_SetObject(PyExc_StopIteration, res); - Py_DECREF(res); - } - - it->future = NULL; - Py_DECREF(fut); - return NULL; -} - -static PyObject * -FutureIter_send(futureiterobject *self, PyObject *arg) -{ - if (arg != Py_None) { - PyErr_Format(PyExc_TypeError, - "can't send non-None value to a FutureIter"); - return NULL; - } - return FutureIter_iternext(self); -} - -static PyObject * -FutureIter_throw(futureiterobject *self, PyObject *args) -{ - PyObject *type=NULL, *val=NULL, *tb=NULL; - if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) - return NULL; - - if (val == Py_None) { - val = NULL; - } - if (tb == Py_None) { - tb = NULL; - } - - Py_CLEAR(self->future); - - if (tb != NULL) { - PyErr_Restore(type, val, tb); - } - else if (val != NULL) { - PyErr_SetObject(type, val); - } - else { - if (PyExceptionClass_Check(type)) { - val = PyObject_CallObject(type, NULL); - } - else { - val = type; - assert (PyExceptionInstance_Check(val)); - type = (PyObject*)Py_TYPE(val); - assert (PyExceptionClass_Check(type)); - } - PyErr_SetObject(type, val); - } - return FutureIter_iternext(self); -} - -static PyObject * -FutureIter_close(futureiterobject *self, PyObject *arg) -{ - Py_CLEAR(self->future); - Py_RETURN_NONE; -} - -static int -FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->future); - return 0; -} - -static PyMethodDef FutureIter_methods[] = { - {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, - {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, - {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, - {NULL, NULL} /* Sentinel */ -}; - -static PyTypeObject FutureIterType = { - PyVarObject_HEAD_INIT(0, 0) - "_futures.FutureIter", - sizeof(futureiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)FutureIter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 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 */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)FutureIter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)FutureIter_iternext, /* tp_iternext */ - FutureIter_methods, /* tp_methods */ - 0, /* tp_members */ -}; - -static PyObject * -new_future_iter(PyObject *fut) -{ - futureiterobject *it; - - if (!PyObject_TypeCheck(fut, &FutureType)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_GC_New(futureiterobject, &FutureIterType); - if (it == NULL) { - return NULL; - } - Py_INCREF(fut); - it->future = (FutureObj*)fut; - PyObject_GC_Track(it); - return (PyObject*)it; -} - -/*********************** Module **************************/ - -PyDoc_STRVAR(module_doc, "Fast asyncio.Future implementation.\n"); - -PyObject * -_init_module(PyObject *self, PyObject *args) -{ - PyObject *extract_stack; - PyObject *get_event_loop; - PyObject *repr_info_func; - PyObject *invalidStateError; - PyObject *cancelledError; - - if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, - &extract_stack, - &get_event_loop, - &repr_info_func, - &invalidStateError, - &cancelledError)) { - return NULL; - } - - Py_INCREF(extract_stack); - Py_XSETREF(traceback_extract_stack, extract_stack); - - Py_INCREF(get_event_loop); - Py_XSETREF(asyncio_get_event_loop, get_event_loop); - - Py_INCREF(repr_info_func); - Py_XSETREF(asyncio_repr_info_func, repr_info_func); - - Py_INCREF(invalidStateError); - Py_XSETREF(asyncio_InvalidStateError, invalidStateError); - - Py_INCREF(cancelledError); - Py_XSETREF(asyncio_CancelledError, cancelledError); - - _futuremod_ready = 1; - - Py_RETURN_NONE; -} - - -static struct PyMethodDef futuresmod_methods[] = { - {"_init_module", _init_module, METH_VARARGS, NULL}, - {NULL, NULL} -}; - - -static struct PyModuleDef _futuresmodule = { - PyModuleDef_HEAD_INIT, /* m_base */ - "_futures", /* m_name */ - module_doc, /* m_doc */ - -1, /* m_size */ - futuresmod_methods, /* m_methods */ - NULL, /* m_slots */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; - - -PyMODINIT_FUNC -PyInit__futures(void) -{ - if (PyType_Ready(&FutureType) < 0) { - return NULL; - } - if (PyType_Ready(&FutureIterType) < 0) { - return NULL; - } - - PyObject *m = PyModule_Create(&_futuresmodule); - if (m == NULL) { - return NULL; - } - - Py_INCREF(&FutureType); - if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { - Py_DECREF(&FutureType); - return NULL; - } - - return m; -} diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -213,6 +213,7 @@ + @@ -221,7 +222,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -446,6 +446,9 @@ + + Modules + Modules @@ -470,9 +473,6 @@ Modules - - Modules - Modules diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -657,8 +657,8 @@ depends=['unicodedata_db.h', 'unicodename_db.h']) ) # _opcode module exts.append( Extension('_opcode', ['_opcode.c']) ) - # Fast asyncio Future implementation - exts.append( Extension("_futures", ["_futuresmodule.c"]) ) + # asyncio speedups + exts.append( Extension("_asyncio", ["_asynciomodule.c"]) ) # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 15 02:41:17 2016 From: python-checkins at python.org (inada.naoki) Date: Sat, 15 Oct 2016 06:41:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDI4?= =?utf-8?q?=3A_Rename_=5Ffutures_module_to_=5Fasyncio=2E?= Message-ID: <20161015064117.117200.97471.632D4203@psf.io> https://hg.python.org/cpython/rev/9d06fdedae2b changeset: 104504:9d06fdedae2b branch: 3.6 parent: 104501:1f2ca7e4b64e user: INADA Naoki date: Sat Oct 15 15:39:19 2016 +0900 summary: Issue #28428: Rename _futures module to _asyncio. It will have more speedup functions or classes other than asyncio.Future. files: Lib/asyncio/futures.py | 6 +- Modules/Setup.dist | 2 +- Modules/_asynciomodule.c | 1034 ++++++++++++++++ Modules/_futuresmodule.c | 1034 ---------------- PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 6 +- setup.py | 4 +- 7 files changed, 1044 insertions(+), 1044 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -432,18 +432,18 @@ try: - import _futures + import _asyncio except ImportError: pass else: - _futures._init_module( + _asyncio._init_module( traceback.extract_stack, events.get_event_loop, _future_repr_info, InvalidStateError, CancelledError) - Future = _futures.Future + Future = _asyncio.Future def _chain_future(source, destination): diff --git a/Modules/Setup.dist b/Modules/Setup.dist --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -181,7 +181,7 @@ #_datetime _datetimemodule.c # datetime accelerator #_bisect _bisectmodule.c # Bisection algorithms #_heapq _heapqmodule.c # Heap queue algorithm -#_futures _futuresmodule.c # Fast asyncio Future +#_asyncio _asynciomodule.c # Fast asyncio Future #unicodedata unicodedata.c # static Unicode character database diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c new file mode 100644 --- /dev/null +++ b/Modules/_asynciomodule.c @@ -0,0 +1,1034 @@ +#include "Python.h" +#include "structmember.h" + + +/* identifiers used from some functions */ +_Py_IDENTIFIER(call_soon); + + +/* State of the _asyncio module */ +static int _asynciomod_ready; +static PyObject *traceback_extract_stack; +static PyObject *asyncio_get_event_loop; +static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_InvalidStateError; +static PyObject *asyncio_CancelledError; + + +/* Get FutureIter from Future */ +static PyObject* new_future_iter(PyObject *fut); + + +/* make sure module state is initialized and ready to be used. */ +static int +_AsyncioMod_EnsureState(void) +{ + if (!_asynciomod_ready) { + PyErr_SetString(PyExc_RuntimeError, + "_asyncio module wasn't properly initialized"); + return -1; + } + return 0; +} + + +typedef enum { + STATE_PENDING, + STATE_CANCELLED, + STATE_FINISHED +} fut_state; + + +typedef struct { + PyObject_HEAD + PyObject *fut_loop; + PyObject *fut_callbacks; + PyObject *fut_exception; + PyObject *fut_result; + PyObject *fut_source_tb; + fut_state fut_state; + int fut_log_tb; + int fut_blocking; + PyObject *dict; + PyObject *fut_weakreflist; +} FutureObj; + + +static int +_schedule_callbacks(FutureObj *fut) +{ + Py_ssize_t len; + PyObject* iters; + int i; + + if (fut->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); + return -1; + } + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return 0; + } + + iters = PyList_GetSlice(fut->fut_callbacks, 0, len); + if (iters == NULL) { + return -1; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { + Py_DECREF(iters); + return -1; + } + + for (i = 0; i < len; i++) { + PyObject *handle = NULL; + PyObject *cb = PyList_GET_ITEM(iters, i); + + handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); + + if (handle == NULL) { + Py_DECREF(iters); + return -1; + } + else { + Py_DECREF(handle); + } + } + + Py_DECREF(iters); + return 0; +} + +static int +FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"loop", NULL}; + PyObject *loop = NULL; + PyObject *res = NULL; + _Py_IDENTIFIER(get_debug); + + if (_AsyncioMod_EnsureState()) { + return -1; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { + return -1; + } + if (loop == NULL || loop == Py_None) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return -1; + } + } + else { + Py_INCREF(loop); + } + Py_CLEAR(fut->fut_loop); + fut->fut_loop = loop; + + res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); + if (res == NULL) { + return -1; + } + if (PyObject_IsTrue(res)) { + Py_CLEAR(res); + fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); + if (fut->fut_source_tb == NULL) { + return -1; + } + } + else { + Py_CLEAR(res); + } + + fut->fut_callbacks = PyList_New(0); + if (fut->fut_callbacks == NULL) { + return -1; + } + return 0; +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +PyDoc_STRVAR(pydoc_result, + "Return the result this future represents.\n" + "\n" + "If the future has been cancelled, raises CancelledError. If the\n" + "future's result isn't yet available, raises InvalidStateError. If\n" + "the future is done and has an exception set, this exception is raised." +); + +static PyObject * +FutureObj_result(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + PyObject *type = NULL; + type = PyExceptionInstance_Class(fut->fut_exception); + PyErr_SetObject(type, fut->fut_exception); + return NULL; + } + + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +PyDoc_STRVAR(pydoc_exception, + "Return the exception that was set on this future.\n" + "\n" + "The exception (or None if no exception was set) is returned only if\n" + "the future is done. If the future has been cancelled, raises\n" + "CancelledError. If the future isn't done yet, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_exception(FutureObj *fut, PyObject *arg) +{ + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (fut->fut_exception != NULL) { + fut->fut_log_tb = 0; + Py_INCREF(fut->fut_exception); + return fut->fut_exception; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_result, + "Mark the future done and set its result.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_result(FutureObj *fut, PyObject *res) +{ + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + Py_INCREF(res); + fut->fut_result = res; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_exception, + "Mark the future done and set an exception.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_exception(FutureObj *fut, PyObject *exc) +{ + PyObject *exc_val = NULL; + + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + if (PyExceptionClass_Check(exc)) { + exc_val = PyObject_CallObject(exc, NULL); + if (exc_val == NULL) { + return NULL; + } + } + else { + exc_val = exc; + Py_INCREF(exc_val); + } + if (!PyExceptionInstance_Check(exc_val)) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, "invalid exception object"); + return NULL; + } + if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, + "StopIteration interacts badly with generators " + "and cannot be raised into a Future"); + return NULL; + } + + fut->fut_exception = exc_val; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + fut->fut_log_tb = 1; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_add_done_callback, + "Add a callback to be run when the future becomes done.\n" + "\n" + "The callback is called with a single argument - the future object. If\n" + "the future is already done when this is called, the callback is\n" + "scheduled with call_soon."; +); + +static PyObject * +FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + PyObject *handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); + + if (handle == NULL) { + return NULL; + } + else { + Py_DECREF(handle); + } + } + else { + int err = PyList_Append(fut->fut_callbacks, arg); + if (err != 0) { + return NULL; + } + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_remove_done_callback, + "Remove all instances of a callback from the \"call when done\" list.\n" + "\n" + "Returns the number of callbacks removed." +); + +static PyObject * +FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +{ + PyObject *newlist; + Py_ssize_t len, i, j=0; + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return PyLong_FromSsize_t(0); + } + + newlist = PyList_New(len); + if (newlist == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + int ret; + PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + + if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + goto fail; + } + if (ret == 0) { + Py_INCREF(item); + PyList_SET_ITEM(newlist, j, item); + j++; + } + } + + if (PyList_SetSlice(newlist, j, len, NULL) < 0) { + goto fail; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + goto fail; + } + Py_DECREF(newlist); + return PyLong_FromSsize_t(len - j); + +fail: + Py_DECREF(newlist); + return NULL; +} + +PyDoc_STRVAR(pydoc_cancel, + "Cancel the future and schedule callbacks.\n" + "\n" + "If the future is already done or cancelled, return False. Otherwise,\n" + "change the future's state to cancelled, schedule the callbacks and\n" + "return True." +); + +static PyObject * +FutureObj_cancel(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); + +static PyObject * +FutureObj_cancelled(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(pydoc_done, + "Return True if the future is done.\n" + "\n" + "Done means either that a result / exception are available, or that the\n" + "future was cancelled." +); + +static PyObject * +FutureObj_done(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_PENDING) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject * +FutureObj_get_blocking(FutureObj *fut) +{ + if (fut->fut_blocking) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static int +FutureObj_set_blocking(FutureObj *fut, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; + } + fut->fut_blocking = is_true; + return 0; +} + +static PyObject * +FutureObj_get_log_traceback(FutureObj *fut) +{ + if (fut->fut_log_tb) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +FutureObj_get_loop(FutureObj *fut) +{ + if (fut->fut_loop == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_loop); + return fut->fut_loop; +} + +static PyObject * +FutureObj_get_callbacks(FutureObj *fut) +{ + if (fut->fut_callbacks == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_callbacks); + return fut->fut_callbacks; +} + +static PyObject * +FutureObj_get_result(FutureObj *fut) +{ + if (fut->fut_result == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +static PyObject * +FutureObj_get_exception(FutureObj *fut) +{ + if (fut->fut_exception == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_exception); + return fut->fut_exception; +} + +static PyObject * +FutureObj_get_source_traceback(FutureObj *fut) +{ + if (fut->fut_source_tb == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_source_tb); + return fut->fut_source_tb; +} + +static PyObject * +FutureObj_get_state(FutureObj *fut) +{ + _Py_IDENTIFIER(PENDING); + _Py_IDENTIFIER(CANCELLED); + _Py_IDENTIFIER(FINISHED); + PyObject *ret = NULL; + + switch (fut->fut_state) { + case STATE_PENDING: + ret = _PyUnicode_FromId(&PyId_PENDING); + break; + case STATE_CANCELLED: + ret = _PyUnicode_FromId(&PyId_CANCELLED); + break; + case STATE_FINISHED: + ret = _PyUnicode_FromId(&PyId_FINISHED); + break; + default: + assert (0); + } + Py_INCREF(ret); + return ret; +} + +static PyObject* +FutureObj__repr_info(FutureObj *fut) +{ + if (asyncio_repr_info_func == NULL) { + return PyList_New(0); + } + return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); +} + +static PyObject * +FutureObj_repr(FutureObj *fut) +{ + _Py_IDENTIFIER(_repr_info); + + PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed + if (_repr_info == NULL) { + return NULL; + } + + PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, + NULL); + if (rinfo == NULL) { + return NULL; + } + + PyObject *sp = PyUnicode_FromString(" "); + if (sp == NULL) { + Py_DECREF(rinfo); + return NULL; + } + + PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); + Py_DECREF(sp); + Py_DECREF(rinfo); + if (rinfo_s == NULL) { + return NULL; + } + + PyObject *rstr = NULL; + PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), + "__name__"); + if (type_name != NULL) { + rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); + Py_DECREF(type_name); + } + Py_DECREF(rinfo_s); + return rstr; +} + +static void +FutureObj_finalize(FutureObj *fut) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(exception); + _Py_IDENTIFIER(future); + _Py_IDENTIFIER(source_traceback); + + if (!fut->fut_log_tb) { + return; + } + assert(fut->fut_exception != NULL); + fut->fut_log_tb = 0;; + + PyObject *error_type, *error_value, *error_traceback; + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyObject *context = NULL; + PyObject *type_name = NULL; + PyObject *message = NULL; + PyObject *func = NULL; + PyObject *res = NULL; + + context = PyDict_New(); + if (context == NULL) { + goto finally; + } + + type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); + if (type_name == NULL) { + goto finally; + } + + message = PyUnicode_FromFormat( + "%S exception was never retrieved", type_name); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || + _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { + goto finally; + } + if (fut->fut_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + fut->fut_source_tb) < 0) { + goto finally; + } + } + + func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(type_name); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + + +static PyAsyncMethods FutureType_as_async = { + (unaryfunc)new_future_iter, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef FutureType_methods[] = { + {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, + {"add_done_callback", + (PyCFunction)FutureObj_add_done_callback, + METH_O, pydoc_add_done_callback}, + {"remove_done_callback", + (PyCFunction)FutureObj_remove_done_callback, + METH_O, pydoc_remove_done_callback}, + {"set_result", + (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, + {"set_exception", + (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, + {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, + {"cancelled", + (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, + {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, + {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, + {"exception", + (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef FutureType_getsetlist[] = { + {"_state", (getter)FutureObj_get_state, NULL, NULL}, + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, + (setter)FutureObj_set_blocking, NULL}, + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, + {"_result", (getter)FutureObj_get_result, NULL, NULL}, + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static void FutureObj_dealloc(PyObject *self); + +static PyTypeObject FutureType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.Future", + sizeof(FutureObj), /* tp_basicsize */ + .tp_dealloc = FutureObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = "Fast asyncio.Future implementation.", + .tp_traverse = (traverseproc)FutureObj_traverse, + .tp_clear = (inquiry)FutureObj_clear, + .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), + .tp_iter = (getiterfunc)new_future_iter, + .tp_methods = FutureType_methods, + .tp_getset = FutureType_getsetlist, + .tp_dictoffset = offsetof(FutureObj, dict), + .tp_init = (initproc)FutureObj_init, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)FutureObj_finalize, +}; + +static void +FutureObj_dealloc(PyObject *self) +{ + FutureObj *fut = (FutureObj *)self; + + if (Py_TYPE(fut) == &FutureType) { + /* When fut is subclass of Future, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (fut->fut_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + FutureObj_clear(fut); + Py_TYPE(fut)->tp_free(fut); +} + + +/*********************** Future Iterator **************************/ + +typedef struct { + PyObject_HEAD + FutureObj *future; +} futureiterobject; + +static void +FutureIter_dealloc(futureiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->future); + PyObject_GC_Del(it); +} + +static PyObject * +FutureIter_iternext(futureiterobject *it) +{ + PyObject *res; + FutureObj *fut = it->future; + + if (fut == NULL) { + return NULL; + } + + if (fut->fut_state == STATE_PENDING) { + if (!fut->fut_blocking) { + fut->fut_blocking = 1; + Py_INCREF(fut); + return (PyObject *)fut; + } + PyErr_Format(PyExc_AssertionError, + "yield from wasn't used with future"); + return NULL; + } + + res = FutureObj_result(fut, NULL); + if (res != NULL) { + // normal result + PyErr_SetObject(PyExc_StopIteration, res); + Py_DECREF(res); + } + + it->future = NULL; + Py_DECREF(fut); + return NULL; +} + +static PyObject * +FutureIter_send(futureiterobject *self, PyObject *arg) +{ + if (arg != Py_None) { + PyErr_Format(PyExc_TypeError, + "can't send non-None value to a FutureIter"); + return NULL; + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_throw(futureiterobject *self, PyObject *args) +{ + PyObject *type=NULL, *val=NULL, *tb=NULL; + if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) + return NULL; + + if (val == Py_None) { + val = NULL; + } + if (tb == Py_None) { + tb = NULL; + } + + Py_CLEAR(self->future); + + if (tb != NULL) { + PyErr_Restore(type, val, tb); + } + else if (val != NULL) { + PyErr_SetObject(type, val); + } + else { + if (PyExceptionClass_Check(type)) { + val = PyObject_CallObject(type, NULL); + } + else { + val = type; + assert (PyExceptionInstance_Check(val)); + type = (PyObject*)Py_TYPE(val); + assert (PyExceptionClass_Check(type)); + } + PyErr_SetObject(type, val); + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_close(futureiterobject *self, PyObject *arg) +{ + Py_CLEAR(self->future); + Py_RETURN_NONE; +} + +static int +FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->future); + return 0; +} + +static PyMethodDef FutureIter_methods[] = { + {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, + {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, + {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, + {NULL, NULL} /* Sentinel */ +}; + +static PyTypeObject FutureIterType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.FutureIter", + sizeof(futureiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)FutureIter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 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 */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)FutureIter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)FutureIter_iternext, /* tp_iternext */ + FutureIter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +static PyObject * +new_future_iter(PyObject *fut) +{ + futureiterobject *it; + + if (!PyObject_TypeCheck(fut, &FutureType)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(futureiterobject, &FutureIterType); + if (it == NULL) { + return NULL; + } + Py_INCREF(fut); + it->future = (FutureObj*)fut; + PyObject_GC_Track(it); + return (PyObject*)it; +} + +/*********************** Module **************************/ + +PyDoc_STRVAR(module_doc, "asyncio speedups.\n"); + +PyObject * +_init_module(PyObject *self, PyObject *args) +{ + PyObject *extract_stack; + PyObject *get_event_loop; + PyObject *repr_info_func; + PyObject *invalidStateError; + PyObject *cancelledError; + + if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, + &extract_stack, + &get_event_loop, + &repr_info_func, + &invalidStateError, + &cancelledError)) { + return NULL; + } + + Py_INCREF(extract_stack); + Py_XSETREF(traceback_extract_stack, extract_stack); + + Py_INCREF(get_event_loop); + Py_XSETREF(asyncio_get_event_loop, get_event_loop); + + Py_INCREF(repr_info_func); + Py_XSETREF(asyncio_repr_info_func, repr_info_func); + + Py_INCREF(invalidStateError); + Py_XSETREF(asyncio_InvalidStateError, invalidStateError); + + Py_INCREF(cancelledError); + Py_XSETREF(asyncio_CancelledError, cancelledError); + + _asynciomod_ready = 1; + + Py_RETURN_NONE; +} + + +static struct PyMethodDef asynciomod_methods[] = { + {"_init_module", _init_module, METH_VARARGS, NULL}, + {NULL, NULL} +}; + + +static struct PyModuleDef _asynciomodule = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_asyncio", /* m_name */ + module_doc, /* m_doc */ + -1, /* m_size */ + asynciomod_methods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + + +PyMODINIT_FUNC +PyInit__asyncio(void) +{ + if (PyType_Ready(&FutureType) < 0) { + return NULL; + } + if (PyType_Ready(&FutureIterType) < 0) { + return NULL; + } + + PyObject *m = PyModule_Create(&_asynciomodule); + if (m == NULL) { + return NULL; + } + + Py_INCREF(&FutureType); + if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { + Py_DECREF(&FutureType); + return NULL; + } + + return m; +} diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c deleted file mode 100644 --- a/Modules/_futuresmodule.c +++ /dev/null @@ -1,1034 +0,0 @@ -#include "Python.h" -#include "structmember.h" - - -/* identifiers used from some functions */ -_Py_IDENTIFIER(call_soon); - - -/* State of the _futures module */ -static int _futuremod_ready; -static PyObject *traceback_extract_stack; -static PyObject *asyncio_get_event_loop; -static PyObject *asyncio_repr_info_func; -static PyObject *asyncio_InvalidStateError; -static PyObject *asyncio_CancelledError; - - -/* Get FutureIter from Future */ -static PyObject* new_future_iter(PyObject *fut); - - -/* make sure module state is initialized and ready to be used. */ -static int -_FuturesMod_EnsureState(void) -{ - if (!_futuremod_ready) { - PyErr_SetString(PyExc_RuntimeError, - "_futures module wasn't properly initialized"); - return -1; - } - return 0; -} - - -typedef enum { - STATE_PENDING, - STATE_CANCELLED, - STATE_FINISHED -} fut_state; - - -typedef struct { - PyObject_HEAD - PyObject *fut_loop; - PyObject *fut_callbacks; - PyObject *fut_exception; - PyObject *fut_result; - PyObject *fut_source_tb; - fut_state fut_state; - int fut_log_tb; - int fut_blocking; - PyObject *dict; - PyObject *fut_weakreflist; -} FutureObj; - - -static int -_schedule_callbacks(FutureObj *fut) -{ - Py_ssize_t len; - PyObject* iters; - int i; - - if (fut->fut_callbacks == NULL) { - PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); - return -1; - } - - len = PyList_GET_SIZE(fut->fut_callbacks); - if (len == 0) { - return 0; - } - - iters = PyList_GetSlice(fut->fut_callbacks, 0, len); - if (iters == NULL) { - return -1; - } - if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { - Py_DECREF(iters); - return -1; - } - - for (i = 0; i < len; i++) { - PyObject *handle = NULL; - PyObject *cb = PyList_GET_ITEM(iters, i); - - handle = _PyObject_CallMethodId( - fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); - - if (handle == NULL) { - Py_DECREF(iters); - return -1; - } - else { - Py_DECREF(handle); - } - } - - Py_DECREF(iters); - return 0; -} - -static int -FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"loop", NULL}; - PyObject *loop = NULL; - PyObject *res = NULL; - _Py_IDENTIFIER(get_debug); - - if (_FuturesMod_EnsureState()) { - return -1; - } - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { - return -1; - } - if (loop == NULL || loop == Py_None) { - loop = PyObject_CallObject(asyncio_get_event_loop, NULL); - if (loop == NULL) { - return -1; - } - } - else { - Py_INCREF(loop); - } - Py_CLEAR(fut->fut_loop); - fut->fut_loop = loop; - - res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); - if (res == NULL) { - return -1; - } - if (PyObject_IsTrue(res)) { - Py_CLEAR(res); - fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); - if (fut->fut_source_tb == NULL) { - return -1; - } - } - else { - Py_CLEAR(res); - } - - fut->fut_callbacks = PyList_New(0); - if (fut->fut_callbacks == NULL) { - return -1; - } - return 0; -} - -static int -FutureObj_clear(FutureObj *fut) -{ - Py_CLEAR(fut->fut_loop); - Py_CLEAR(fut->fut_callbacks); - Py_CLEAR(fut->fut_result); - Py_CLEAR(fut->fut_exception); - Py_CLEAR(fut->fut_source_tb); - Py_CLEAR(fut->dict); - return 0; -} - -static int -FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) -{ - Py_VISIT(fut->fut_loop); - Py_VISIT(fut->fut_callbacks); - Py_VISIT(fut->fut_result); - Py_VISIT(fut->fut_exception); - Py_VISIT(fut->fut_source_tb); - Py_VISIT(fut->dict); - return 0; -} - -PyDoc_STRVAR(pydoc_result, - "Return the result this future represents.\n" - "\n" - "If the future has been cancelled, raises CancelledError. If the\n" - "future's result isn't yet available, raises InvalidStateError. If\n" - "the future is done and has an exception set, this exception is raised." -); - -static PyObject * -FutureObj_result(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - fut->fut_log_tb = 0; - if (fut->fut_exception != NULL) { - PyObject *type = NULL; - type = PyExceptionInstance_Class(fut->fut_exception); - PyErr_SetObject(type, fut->fut_exception); - return NULL; - } - - Py_INCREF(fut->fut_result); - return fut->fut_result; -} - -PyDoc_STRVAR(pydoc_exception, - "Return the exception that was set on this future.\n" - "\n" - "The exception (or None if no exception was set) is returned only if\n" - "the future is done. If the future has been cancelled, raises\n" - "CancelledError. If the future isn't done yet, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_exception(FutureObj *fut, PyObject *arg) -{ - if (_FuturesMod_EnsureState()) { - return NULL; - } - - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - if (fut->fut_exception != NULL) { - fut->fut_log_tb = 0; - Py_INCREF(fut->fut_exception); - return fut->fut_exception; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_set_result, - "Mark the future done and set its result.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_set_result(FutureObj *fut, PyObject *res) -{ - if (_FuturesMod_EnsureState()) { - return NULL; - } - - if (fut->fut_state != STATE_PENDING) { - PyErr_SetString(asyncio_InvalidStateError, "invalid state"); - return NULL; - } - - Py_INCREF(res); - fut->fut_result = res; - fut->fut_state = STATE_FINISHED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_set_exception, - "Mark the future done and set an exception.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_set_exception(FutureObj *fut, PyObject *exc) -{ - PyObject *exc_val = NULL; - - if (_FuturesMod_EnsureState()) { - return NULL; - } - - if (fut->fut_state != STATE_PENDING) { - PyErr_SetString(asyncio_InvalidStateError, "invalid state"); - return NULL; - } - - if (PyExceptionClass_Check(exc)) { - exc_val = PyObject_CallObject(exc, NULL); - if (exc_val == NULL) { - return NULL; - } - } - else { - exc_val = exc; - Py_INCREF(exc_val); - } - if (!PyExceptionInstance_Check(exc_val)) { - Py_DECREF(exc_val); - PyErr_SetString(PyExc_TypeError, "invalid exception object"); - return NULL; - } - if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { - Py_DECREF(exc_val); - PyErr_SetString(PyExc_TypeError, - "StopIteration interacts badly with generators " - "and cannot be raised into a Future"); - return NULL; - } - - fut->fut_exception = exc_val; - fut->fut_state = STATE_FINISHED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - - fut->fut_log_tb = 1; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_add_done_callback, - "Add a callback to be run when the future becomes done.\n" - "\n" - "The callback is called with a single argument - the future object. If\n" - "the future is already done when this is called, the callback is\n" - "scheduled with call_soon."; -); - -static PyObject * -FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state != STATE_PENDING) { - PyObject *handle = _PyObject_CallMethodId( - fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); - - if (handle == NULL) { - return NULL; - } - else { - Py_DECREF(handle); - } - } - else { - int err = PyList_Append(fut->fut_callbacks, arg); - if (err != 0) { - return NULL; - } - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_remove_done_callback, - "Remove all instances of a callback from the \"call when done\" list.\n" - "\n" - "Returns the number of callbacks removed." -); - -static PyObject * -FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) -{ - PyObject *newlist; - Py_ssize_t len, i, j=0; - - len = PyList_GET_SIZE(fut->fut_callbacks); - if (len == 0) { - return PyLong_FromSsize_t(0); - } - - newlist = PyList_New(len); - if (newlist == NULL) { - return NULL; - } - - for (i = 0; i < len; i++) { - int ret; - PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); - - if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { - goto fail; - } - if (ret == 0) { - Py_INCREF(item); - PyList_SET_ITEM(newlist, j, item); - j++; - } - } - - if (PyList_SetSlice(newlist, j, len, NULL) < 0) { - goto fail; - } - if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { - goto fail; - } - Py_DECREF(newlist); - return PyLong_FromSsize_t(len - j); - -fail: - Py_DECREF(newlist); - return NULL; -} - -PyDoc_STRVAR(pydoc_cancel, - "Cancel the future and schedule callbacks.\n" - "\n" - "If the future is already done or cancelled, return False. Otherwise,\n" - "change the future's state to cancelled, schedule the callbacks and\n" - "return True." -); - -static PyObject * -FutureObj_cancel(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state != STATE_PENDING) { - Py_RETURN_FALSE; - } - fut->fut_state = STATE_CANCELLED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - - Py_RETURN_TRUE; -} - -PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); - -static PyObject * -FutureObj_cancelled(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -PyDoc_STRVAR(pydoc_done, - "Return True if the future is done.\n" - "\n" - "Done means either that a result / exception are available, or that the\n" - "future was cancelled." -); - -static PyObject * -FutureObj_done(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_PENDING) { - Py_RETURN_FALSE; - } - else { - Py_RETURN_TRUE; - } -} - -static PyObject * -FutureObj_get_blocking(FutureObj *fut) -{ - if (fut->fut_blocking) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -static int -FutureObj_set_blocking(FutureObj *fut, PyObject *val) -{ - int is_true = PyObject_IsTrue(val); - if (is_true < 0) { - return -1; - } - fut->fut_blocking = is_true; - return 0; -} - -static PyObject * -FutureObj_get_log_traceback(FutureObj *fut) -{ - if (fut->fut_log_tb) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -static PyObject * -FutureObj_get_loop(FutureObj *fut) -{ - if (fut->fut_loop == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_loop); - return fut->fut_loop; -} - -static PyObject * -FutureObj_get_callbacks(FutureObj *fut) -{ - if (fut->fut_callbacks == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_callbacks); - return fut->fut_callbacks; -} - -static PyObject * -FutureObj_get_result(FutureObj *fut) -{ - if (fut->fut_result == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_result); - return fut->fut_result; -} - -static PyObject * -FutureObj_get_exception(FutureObj *fut) -{ - if (fut->fut_exception == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_exception); - return fut->fut_exception; -} - -static PyObject * -FutureObj_get_source_traceback(FutureObj *fut) -{ - if (fut->fut_source_tb == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(fut->fut_source_tb); - return fut->fut_source_tb; -} - -static PyObject * -FutureObj_get_state(FutureObj *fut) -{ - _Py_IDENTIFIER(PENDING); - _Py_IDENTIFIER(CANCELLED); - _Py_IDENTIFIER(FINISHED); - PyObject *ret = NULL; - - switch (fut->fut_state) { - case STATE_PENDING: - ret = _PyUnicode_FromId(&PyId_PENDING); - break; - case STATE_CANCELLED: - ret = _PyUnicode_FromId(&PyId_CANCELLED); - break; - case STATE_FINISHED: - ret = _PyUnicode_FromId(&PyId_FINISHED); - break; - default: - assert (0); - } - Py_INCREF(ret); - return ret; -} - -static PyObject* -FutureObj__repr_info(FutureObj *fut) -{ - if (asyncio_repr_info_func == NULL) { - return PyList_New(0); - } - return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); -} - -static PyObject * -FutureObj_repr(FutureObj *fut) -{ - _Py_IDENTIFIER(_repr_info); - - PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed - if (_repr_info == NULL) { - return NULL; - } - - PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, - NULL); - if (rinfo == NULL) { - return NULL; - } - - PyObject *sp = PyUnicode_FromString(" "); - if (sp == NULL) { - Py_DECREF(rinfo); - return NULL; - } - - PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); - Py_DECREF(sp); - Py_DECREF(rinfo); - if (rinfo_s == NULL) { - return NULL; - } - - PyObject *rstr = NULL; - PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), - "__name__"); - if (type_name != NULL) { - rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); - Py_DECREF(type_name); - } - Py_DECREF(rinfo_s); - return rstr; -} - -static void -FutureObj_finalize(FutureObj *fut) -{ - _Py_IDENTIFIER(call_exception_handler); - _Py_IDENTIFIER(message); - _Py_IDENTIFIER(exception); - _Py_IDENTIFIER(future); - _Py_IDENTIFIER(source_traceback); - - if (!fut->fut_log_tb) { - return; - } - assert(fut->fut_exception != NULL); - fut->fut_log_tb = 0;; - - PyObject *error_type, *error_value, *error_traceback; - /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - PyObject *context = NULL; - PyObject *type_name = NULL; - PyObject *message = NULL; - PyObject *func = NULL; - PyObject *res = NULL; - - context = PyDict_New(); - if (context == NULL) { - goto finally; - } - - type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); - if (type_name == NULL) { - goto finally; - } - - message = PyUnicode_FromFormat( - "%S exception was never retrieved", type_name); - if (message == NULL) { - goto finally; - } - - if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || - _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || - _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { - goto finally; - } - if (fut->fut_source_tb != NULL) { - if (_PyDict_SetItemId(context, &PyId_source_traceback, - fut->fut_source_tb) < 0) { - goto finally; - } - } - - func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); - if (func != NULL) { - res = _PyObject_CallArg1(func, context); - if (res == NULL) { - PyErr_WriteUnraisable(func); - } - } - -finally: - Py_CLEAR(context); - Py_CLEAR(type_name); - Py_CLEAR(message); - Py_CLEAR(func); - Py_CLEAR(res); - - /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); -} - - -static PyAsyncMethods FutureType_as_async = { - (unaryfunc)new_future_iter, /* am_await */ - 0, /* am_aiter */ - 0 /* am_anext */ -}; - -static PyMethodDef FutureType_methods[] = { - {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, - {"add_done_callback", - (PyCFunction)FutureObj_add_done_callback, - METH_O, pydoc_add_done_callback}, - {"remove_done_callback", - (PyCFunction)FutureObj_remove_done_callback, - METH_O, pydoc_remove_done_callback}, - {"set_result", - (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, - {"set_exception", - (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, - {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, - {"cancelled", - (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, - {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, - {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, - {"exception", - (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, - {NULL, NULL} /* Sentinel */ -}; - -static PyGetSetDef FutureType_getsetlist[] = { - {"_state", (getter)FutureObj_get_state, NULL, NULL}, - {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, - (setter)FutureObj_set_blocking, NULL}, - {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, - {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, - {"_result", (getter)FutureObj_get_result, NULL, NULL}, - {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, - {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, - {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, - {NULL} /* Sentinel */ -}; - -static void FutureObj_dealloc(PyObject *self); - -static PyTypeObject FutureType = { - PyVarObject_HEAD_INIT(0, 0) - "_futures.Future", - sizeof(FutureObj), /* tp_basicsize */ - .tp_dealloc = FutureObj_dealloc, - .tp_as_async = &FutureType_as_async, - .tp_repr = (reprfunc)FutureObj_repr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_FINALIZE, - .tp_doc = "Fast asyncio.Future implementation.", - .tp_traverse = (traverseproc)FutureObj_traverse, - .tp_clear = (inquiry)FutureObj_clear, - .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), - .tp_iter = (getiterfunc)new_future_iter, - .tp_methods = FutureType_methods, - .tp_getset = FutureType_getsetlist, - .tp_dictoffset = offsetof(FutureObj, dict), - .tp_init = (initproc)FutureObj_init, - .tp_new = PyType_GenericNew, - .tp_finalize = (destructor)FutureObj_finalize, -}; - -static void -FutureObj_dealloc(PyObject *self) -{ - FutureObj *fut = (FutureObj *)self; - - if (Py_TYPE(fut) == &FutureType) { - /* When fut is subclass of Future, finalizer is called from - * subtype_dealloc. - */ - if (PyObject_CallFinalizerFromDealloc(self) < 0) { - // resurrected. - return; - } - } - - if (fut->fut_weakreflist != NULL) { - PyObject_ClearWeakRefs(self); - } - - FutureObj_clear(fut); - Py_TYPE(fut)->tp_free(fut); -} - - -/*********************** Future Iterator **************************/ - -typedef struct { - PyObject_HEAD - FutureObj *future; -} futureiterobject; - -static void -FutureIter_dealloc(futureiterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->future); - PyObject_GC_Del(it); -} - -static PyObject * -FutureIter_iternext(futureiterobject *it) -{ - PyObject *res; - FutureObj *fut = it->future; - - if (fut == NULL) { - return NULL; - } - - if (fut->fut_state == STATE_PENDING) { - if (!fut->fut_blocking) { - fut->fut_blocking = 1; - Py_INCREF(fut); - return (PyObject *)fut; - } - PyErr_Format(PyExc_AssertionError, - "yield from wasn't used with future"); - return NULL; - } - - res = FutureObj_result(fut, NULL); - if (res != NULL) { - // normal result - PyErr_SetObject(PyExc_StopIteration, res); - Py_DECREF(res); - } - - it->future = NULL; - Py_DECREF(fut); - return NULL; -} - -static PyObject * -FutureIter_send(futureiterobject *self, PyObject *arg) -{ - if (arg != Py_None) { - PyErr_Format(PyExc_TypeError, - "can't send non-None value to a FutureIter"); - return NULL; - } - return FutureIter_iternext(self); -} - -static PyObject * -FutureIter_throw(futureiterobject *self, PyObject *args) -{ - PyObject *type=NULL, *val=NULL, *tb=NULL; - if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) - return NULL; - - if (val == Py_None) { - val = NULL; - } - if (tb == Py_None) { - tb = NULL; - } - - Py_CLEAR(self->future); - - if (tb != NULL) { - PyErr_Restore(type, val, tb); - } - else if (val != NULL) { - PyErr_SetObject(type, val); - } - else { - if (PyExceptionClass_Check(type)) { - val = PyObject_CallObject(type, NULL); - } - else { - val = type; - assert (PyExceptionInstance_Check(val)); - type = (PyObject*)Py_TYPE(val); - assert (PyExceptionClass_Check(type)); - } - PyErr_SetObject(type, val); - } - return FutureIter_iternext(self); -} - -static PyObject * -FutureIter_close(futureiterobject *self, PyObject *arg) -{ - Py_CLEAR(self->future); - Py_RETURN_NONE; -} - -static int -FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->future); - return 0; -} - -static PyMethodDef FutureIter_methods[] = { - {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, - {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, - {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, - {NULL, NULL} /* Sentinel */ -}; - -static PyTypeObject FutureIterType = { - PyVarObject_HEAD_INIT(0, 0) - "_futures.FutureIter", - sizeof(futureiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)FutureIter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 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 */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)FutureIter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)FutureIter_iternext, /* tp_iternext */ - FutureIter_methods, /* tp_methods */ - 0, /* tp_members */ -}; - -static PyObject * -new_future_iter(PyObject *fut) -{ - futureiterobject *it; - - if (!PyObject_TypeCheck(fut, &FutureType)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_GC_New(futureiterobject, &FutureIterType); - if (it == NULL) { - return NULL; - } - Py_INCREF(fut); - it->future = (FutureObj*)fut; - PyObject_GC_Track(it); - return (PyObject*)it; -} - -/*********************** Module **************************/ - -PyDoc_STRVAR(module_doc, "Fast asyncio.Future implementation.\n"); - -PyObject * -_init_module(PyObject *self, PyObject *args) -{ - PyObject *extract_stack; - PyObject *get_event_loop; - PyObject *repr_info_func; - PyObject *invalidStateError; - PyObject *cancelledError; - - if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, - &extract_stack, - &get_event_loop, - &repr_info_func, - &invalidStateError, - &cancelledError)) { - return NULL; - } - - Py_INCREF(extract_stack); - Py_XSETREF(traceback_extract_stack, extract_stack); - - Py_INCREF(get_event_loop); - Py_XSETREF(asyncio_get_event_loop, get_event_loop); - - Py_INCREF(repr_info_func); - Py_XSETREF(asyncio_repr_info_func, repr_info_func); - - Py_INCREF(invalidStateError); - Py_XSETREF(asyncio_InvalidStateError, invalidStateError); - - Py_INCREF(cancelledError); - Py_XSETREF(asyncio_CancelledError, cancelledError); - - _futuremod_ready = 1; - - Py_RETURN_NONE; -} - - -static struct PyMethodDef futuresmod_methods[] = { - {"_init_module", _init_module, METH_VARARGS, NULL}, - {NULL, NULL} -}; - - -static struct PyModuleDef _futuresmodule = { - PyModuleDef_HEAD_INIT, /* m_base */ - "_futures", /* m_name */ - module_doc, /* m_doc */ - -1, /* m_size */ - futuresmod_methods, /* m_methods */ - NULL, /* m_slots */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; - - -PyMODINIT_FUNC -PyInit__futures(void) -{ - if (PyType_Ready(&FutureType) < 0) { - return NULL; - } - if (PyType_Ready(&FutureIterType) < 0) { - return NULL; - } - - PyObject *m = PyModule_Create(&_futuresmodule); - if (m == NULL) { - return NULL; - } - - Py_INCREF(&FutureType); - if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { - Py_DECREF(&FutureType); - return NULL; - } - - return m; -} diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -213,6 +213,7 @@ + @@ -221,7 +222,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -446,6 +446,9 @@ + + Modules + Modules @@ -470,9 +473,6 @@ Modules - - Modules - Modules diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -656,8 +656,8 @@ depends=['unicodedata_db.h', 'unicodename_db.h']) ) # _opcode module exts.append( Extension('_opcode', ['_opcode.c']) ) - # Fast asyncio Future implementation - exts.append( Extension("_futures", ["_futuresmodule.c"]) ) + # asyncio speedups + exts.append( Extension("_asyncio", ["_asynciomodule.c"]) ) # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 15 15:15:27 2016 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Oct 2016 19:15:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Remove_spurious_article=2E?= Message-ID: <20161015191527.5400.66145.7459363A@psf.io> https://hg.python.org/cpython/rev/f4e9be4c3954 changeset: 104508:f4e9be4c3954 parent: 104505:c2f3b7c56dff parent: 104507:7d38d0404718 user: Ned Deily date: Sat Oct 15 15:14:54 2016 -0400 summary: Remove spurious article. files: Doc/library/pathlib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -841,7 +841,7 @@ If *parents* is false (the default), a missing parent raises :exc:`FileNotFoundError`. - If *exist_ok* is false (the default), an :exc:`FileExistsError` is + If *exist_ok* is false (the default), :exc:`FileExistsError` is raised if the target directory already exists. If *exist_ok* is true, :exc:`FileExistsError` exceptions will be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 15 15:15:27 2016 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Oct 2016 19:15:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Remove_spuriou?= =?utf-8?q?s_article=2E?= Message-ID: <20161015191527.83736.60622.BDFA1D14@psf.io> https://hg.python.org/cpython/rev/22137bc7e260 changeset: 104506:22137bc7e260 branch: 3.5 parent: 104500:5f7d7e079e39 user: Ned Deily date: Sat Oct 15 15:12:03 2016 -0400 summary: Remove spurious article. files: Doc/library/pathlib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -832,7 +832,7 @@ If *parents* is false (the default), a missing parent raises :exc:`FileNotFoundError`. - If *exist_ok* is false (the default), an :exc:`FileExistsError` is + If *exist_ok* is false (the default), :exc:`FileExistsError` is raised if the target directory already exists. If *exist_ok* is true, :exc:`FileExistsError` exceptions will be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 15 15:15:27 2016 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Oct 2016 19:15:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Remove_spurious_article=2E?= Message-ID: <20161015191527.17638.66443.C3C5D83D@psf.io> https://hg.python.org/cpython/rev/7d38d0404718 changeset: 104507:7d38d0404718 branch: 3.6 parent: 104504:9d06fdedae2b parent: 104506:22137bc7e260 user: Ned Deily date: Sat Oct 15 15:13:20 2016 -0400 summary: Remove spurious article. files: Doc/library/pathlib.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -841,7 +841,7 @@ If *parents* is false (the default), a missing parent raises :exc:`FileNotFoundError`. - If *exist_ok* is false (the default), an :exc:`FileExistsError` is + If *exist_ok* is false (the default), :exc:`FileExistsError` is raised if the target directory already exists. If *exist_ok* is true, :exc:`FileExistsError` exceptions will be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 15 22:03:11 2016 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 16 Oct 2016 02:03:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_fix-up_to_apply_the_?= =?utf-8?q?stack_adjustment_macros_consistent_with_the_other?= Message-ID: <20161016020311.83962.3958.B4E2B4F7@psf.io> https://hg.python.org/cpython/rev/ab13c1d0d5e6 changeset: 104509:ab13c1d0d5e6 user: Raymond Hettinger date: Sat Oct 15 19:03:06 2016 -0700 summary: Minor fix-up to apply the stack adjustment macros consistent with the other opcodes files: Python/ceval.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1538,7 +1538,7 @@ TARGET(SET_ADD) { PyObject *v = POP(); - PyObject *set = stack_pointer[-oparg]; + PyObject *set = PEEK(oparg); int err; err = PySet_Add(set, v); Py_DECREF(v); @@ -2796,7 +2796,7 @@ PyObject *map; int err; STACKADJ(-2); - map = stack_pointer[-oparg]; /* dict */ + map = PEEK(oparg); /* dict */ assert(PyDict_CheckExact(map)); err = PyDict_SetItem(map, key, value); /* map[key] = value */ Py_DECREF(value); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 13:15:48 2016 From: python-checkins at python.org (victor.stinner) Date: Sun, 16 Oct 2016 17:15:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2327896=3A_Allow_pa?= =?utf-8?q?ssing_sphinx_options_to_Doc/Makefile?= Message-ID: <20161016171538.20094.22718.0D7A61E9@psf.io> https://hg.python.org/cpython/rev/3884a7e3df1c changeset: 104510:3884a7e3df1c user: Victor Stinner date: Sun Oct 16 19:14:23 2016 +0200 summary: Issue #27896: Allow passing sphinx options to Doc/Makefile Patch written by Julien Palard. files: Doc/Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -162,12 +162,12 @@ # for development releases: always build autobuild-dev: - make dist SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make dist SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' -make suspicious # for quick rebuilds (HTML only) autobuild-dev-html: - make html SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make html SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' # for stable releases: only build if not in pre-release stage (alpha, beta) # release candidate downloads are okay, since the stable tree can be in that stage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 17:46:31 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 16 Oct 2016 21:46:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDMy?= =?utf-8?q?=3A_Fix_first_parameter_name_in_PyUnicode=5FEncodeLocale_docume?= =?utf-8?q?ntation?= Message-ID: <20161016214631.17288.61994.A1D08440@psf.io> https://hg.python.org/cpython/rev/a4889719e3c2 changeset: 104511:a4889719e3c2 branch: 3.5 parent: 104506:22137bc7e260 user: Berker Peksag date: Mon Oct 17 00:45:56 2016 +0300 summary: Issue #28432: Fix first parameter name in PyUnicode_EncodeLocale documentation Patch by Xiang Zhang. files: Doc/c-api/unicode.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -793,7 +793,7 @@ Encode a Unicode object to the current locale encoding. The supported error handlers are ``"strict"`` and ``"surrogateescape"`` (:pep:`383`). The encoder uses ``"strict"`` error handler if - *errors* is ``NULL``. Return a :class:`bytes` object. *str* cannot + *errors* is ``NULL``. Return a :class:`bytes` object. *unicode* cannot contain embedded null characters. Use :c:func:`PyUnicode_EncodeFSDefault` to encode a string to -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 17:46:31 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 16 Oct 2016 21:46:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328432=3A_Merge_from_3=2E5?= Message-ID: <20161016214631.17421.1174.07042A5B@psf.io> https://hg.python.org/cpython/rev/1fc08c283f8f changeset: 104512:1fc08c283f8f branch: 3.6 parent: 104507:7d38d0404718 parent: 104511:a4889719e3c2 user: Berker Peksag date: Mon Oct 17 00:46:37 2016 +0300 summary: Issue #28432: Merge from 3.5 files: Doc/c-api/unicode.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -787,7 +787,7 @@ Encode a Unicode object to the current locale encoding. The supported error handlers are ``"strict"`` and ``"surrogateescape"`` (:pep:`383`). The encoder uses ``"strict"`` error handler if - *errors* is ``NULL``. Return a :class:`bytes` object. *str* cannot + *errors* is ``NULL``. Return a :class:`bytes` object. *unicode* cannot contain embedded null characters. Use :c:func:`PyUnicode_EncodeFSDefault` to encode a string to -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 17:46:31 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 16 Oct 2016 21:46:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328432=3A_Merge_from_3=2E6?= Message-ID: <20161016214631.58755.97210.3F99BBEB@psf.io> https://hg.python.org/cpython/rev/767a78aacd29 changeset: 104513:767a78aacd29 parent: 104510:3884a7e3df1c parent: 104512:1fc08c283f8f user: Berker Peksag date: Mon Oct 17 00:47:03 2016 +0300 summary: Issue #28432: Merge from 3.6 files: Doc/c-api/unicode.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -787,7 +787,7 @@ Encode a Unicode object to the current locale encoding. The supported error handlers are ``"strict"`` and ``"surrogateescape"`` (:pep:`383`). The encoder uses ``"strict"`` error handler if - *errors* is ``NULL``. Return a :class:`bytes` object. *str* cannot + *errors* is ``NULL``. Return a :class:`bytes` object. *unicode* cannot contain embedded null characters. Use :c:func:`PyUnicode_EncodeFSDefault` to encode a string to -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 18:04:24 2016 From: python-checkins at python.org (berker.peksag) Date: Sun, 16 Oct 2016 22:04:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxNzIw?= =?utf-8?q?=3A_Improve_exception_message_when_the_type_of_fromlist_is_unic?= =?utf-8?q?ode?= Message-ID: <20161016220424.5201.77039.B9267DBE@psf.io> https://hg.python.org/cpython/rev/7dd0910e8fbf changeset: 104514:7dd0910e8fbf branch: 2.7 parent: 104503:94f02193f00f user: Berker Peksag date: Mon Oct 17 01:05:04 2016 +0300 summary: Issue #21720: Improve exception message when the type of fromlist is unicode files: Lib/test/test_import.py | 8 ++++++++ Misc/NEWS | 5 +++++ Python/import.c | 5 +++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -415,6 +415,14 @@ finally: rmtree(dir_name) + def test_fromlist_type(self): + with self.assertRaises(TypeError) as cm: + __import__('encodings', fromlist=[u'aliases']) + self.assertIn('must be str, not unicode', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + __import__('encodings', fromlist=[1]) + self.assertIn('must be str, not int', str(cm.exception)) + class PycRewritingTests(unittest.TestCase): # Test that the `co_filename` attribute on code objects always points diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #21720: Improve exception message when the type of fromlist is unicode. + fromlist parameter of __import__() only accepts str in Python 2 and this + will help to identify the problem especially when the unicode_literals + future import is used. + - Issue #26906: Resolving special methods of uninitialized type now causes implicit initialization of the type instead of a fail. diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -2591,8 +2591,9 @@ return 0; } if (!PyString_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "Item in ``from list'' not a string"); + PyErr_Format(PyExc_TypeError, + "Item in ``from list'' must be str, not %.200s", + Py_TYPE(item)->tp_name); Py_DECREF(item); return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 18:42:53 2016 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 16 Oct 2016 22:42:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_remove_extra_P?= =?utf-8?q?yErr=5FFormat_arguments_=28closes_=2328454=29?= Message-ID: <20161016224253.33077.69037.67D48F55@psf.io> https://hg.python.org/cpython/rev/cbe313cd1b55 changeset: 104515:cbe313cd1b55 branch: 3.5 parent: 104511:a4889719e3c2 user: Benjamin Peterson date: Sun Oct 16 15:41:46 2016 -0700 summary: remove extra PyErr_Format arguments (closes #28454) Patch from Xiang Zhang. files: Objects/unicodeobject.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3009,7 +3009,7 @@ "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", encoding, - Py_TYPE(unicode)->tp_name, Py_TYPE(unicode)->tp_name); + Py_TYPE(unicode)->tp_name); Py_DECREF(unicode); goto onError; } @@ -3070,7 +3070,7 @@ "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", encoding, - Py_TYPE(unicode)->tp_name, Py_TYPE(unicode)->tp_name); + Py_TYPE(unicode)->tp_name); Py_DECREF(v); goto onError; } @@ -3398,7 +3398,7 @@ "'%.400s' encoder returned '%.400s' instead of 'bytes'; " "use codecs.encode() to encode to arbitrary types", encoding, - Py_TYPE(v)->tp_name, Py_TYPE(v)->tp_name); + Py_TYPE(v)->tp_name); Py_DECREF(v); return NULL; } @@ -3427,7 +3427,7 @@ "'%.400s' encoder returned '%.400s' instead of 'str'; " "use codecs.encode() to encode to arbitrary types", encoding, - Py_TYPE(v)->tp_name, Py_TYPE(v)->tp_name); + Py_TYPE(v)->tp_name); Py_DECREF(v); goto onError; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 18:42:53 2016 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 16 Oct 2016 22:42:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_merge_3=2E5_=28=2328454=29?= Message-ID: <20161016224253.5161.25191.D3A5EF3A@psf.io> https://hg.python.org/cpython/rev/738579b25d02 changeset: 104516:738579b25d02 branch: 3.6 parent: 104512:1fc08c283f8f parent: 104515:cbe313cd1b55 user: Benjamin Peterson date: Sun Oct 16 15:42:24 2016 -0700 summary: merge 3.5 (#28454) files: Objects/unicodeobject.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3219,7 +3219,7 @@ "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", encoding, - Py_TYPE(unicode)->tp_name, Py_TYPE(unicode)->tp_name); + Py_TYPE(unicode)->tp_name); Py_DECREF(unicode); goto onError; } @@ -3280,7 +3280,7 @@ "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", encoding, - Py_TYPE(unicode)->tp_name, Py_TYPE(unicode)->tp_name); + Py_TYPE(unicode)->tp_name); Py_DECREF(v); goto onError; } @@ -3626,7 +3626,7 @@ "'%.400s' encoder returned '%.400s' instead of 'bytes'; " "use codecs.encode() to encode to arbitrary types", encoding, - Py_TYPE(v)->tp_name, Py_TYPE(v)->tp_name); + Py_TYPE(v)->tp_name); Py_DECREF(v); return NULL; } @@ -3655,7 +3655,7 @@ "'%.400s' encoder returned '%.400s' instead of 'str'; " "use codecs.encode() to encode to arbitrary types", encoding, - Py_TYPE(v)->tp_name, Py_TYPE(v)->tp_name); + Py_TYPE(v)->tp_name); Py_DECREF(v); goto onError; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 18:42:54 2016 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 16 Oct 2016 22:42:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42ICgjMjg0NTQp?= Message-ID: <20161016224254.83839.98312.A64FC388@psf.io> https://hg.python.org/cpython/rev/b37db216c8e0 changeset: 104517:b37db216c8e0 parent: 104513:767a78aacd29 parent: 104516:738579b25d02 user: Benjamin Peterson date: Sun Oct 16 15:42:33 2016 -0700 summary: merge 3.6 (#28454) files: Objects/unicodeobject.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3215,7 +3215,7 @@ "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", encoding, - Py_TYPE(unicode)->tp_name, Py_TYPE(unicode)->tp_name); + Py_TYPE(unicode)->tp_name); Py_DECREF(unicode); goto onError; } @@ -3276,7 +3276,7 @@ "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", encoding, - Py_TYPE(unicode)->tp_name, Py_TYPE(unicode)->tp_name); + Py_TYPE(unicode)->tp_name); Py_DECREF(v); goto onError; } @@ -3622,7 +3622,7 @@ "'%.400s' encoder returned '%.400s' instead of 'bytes'; " "use codecs.encode() to encode to arbitrary types", encoding, - Py_TYPE(v)->tp_name, Py_TYPE(v)->tp_name); + Py_TYPE(v)->tp_name); Py_DECREF(v); return NULL; } @@ -3651,7 +3651,7 @@ "'%.400s' encoder returned '%.400s' instead of 'str'; " "use codecs.encode() to encode to arbitrary types", encoding, - Py_TYPE(v)->tp_name, Py_TYPE(v)->tp_name); + Py_TYPE(v)->tp_name); Py_DECREF(v); goto onError; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 23:14:48 2016 From: python-checkins at python.org (berker.peksag) Date: Mon, 17 Oct 2016 03:14:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDU1?= =?utf-8?q?=3A_Clarify_example_of_overriding_the_convert=5Farg=5Fline=5Fto?= =?utf-8?q?=5Fargs_method?= Message-ID: <20161017031448.12375.36591.B8E8C33B@psf.io> https://hg.python.org/cpython/rev/4f8f7403881f changeset: 104518:4f8f7403881f branch: 3.5 parent: 104515:cbe313cd1b55 user: Berker Peksag date: Mon Oct 17 06:14:17 2016 +0300 summary: Issue #28455: Clarify example of overriding the convert_arg_line_to_args method Patch by Mariatta Wijaya. files: Doc/library/argparse.rst | 9 +++++---- 1 files changed, 5 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 @@ -1958,10 +1958,11 @@ The method is called once per line read from the argument file, in order. A useful override of this method is one that treats each space-separated word - as an argument:: - - def convert_arg_line_to_args(self, arg_line): - return arg_line.split() + as an argument. The following example demonstrates how to do this:: + + class MyArgumentParser(argparse.ArgumentParser): + def convert_arg_line_to_args(self, arg_line): + return arg_line.split() Exiting methods -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 23:14:48 2016 From: python-checkins at python.org (berker.peksag) Date: Mon, 17 Oct 2016 03:14:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328455=3A_Merge_from_3=2E5?= Message-ID: <20161017031448.33170.66545.0C74C3B3@psf.io> https://hg.python.org/cpython/rev/0b29adb5c804 changeset: 104519:0b29adb5c804 branch: 3.6 parent: 104516:738579b25d02 parent: 104518:4f8f7403881f user: Berker Peksag date: Mon Oct 17 06:14:48 2016 +0300 summary: Issue #28455: Merge from 3.5 files: Doc/library/argparse.rst | 9 +++++---- 1 files changed, 5 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 @@ -1958,10 +1958,11 @@ The method is called once per line read from the argument file, in order. A useful override of this method is one that treats each space-separated word - as an argument:: - - def convert_arg_line_to_args(self, arg_line): - return arg_line.split() + as an argument. The following example demonstrates how to do this:: + + class MyArgumentParser(argparse.ArgumentParser): + def convert_arg_line_to_args(self, arg_line): + return arg_line.split() Exiting methods -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 16 23:14:49 2016 From: python-checkins at python.org (berker.peksag) Date: Mon, 17 Oct 2016 03:14:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328455=3A_Merge_from_3=2E6?= Message-ID: <20161017031448.17319.89073.AA72FA3F@psf.io> https://hg.python.org/cpython/rev/a293e5db9083 changeset: 104520:a293e5db9083 parent: 104517:b37db216c8e0 parent: 104519:0b29adb5c804 user: Berker Peksag date: Mon Oct 17 06:15:28 2016 +0300 summary: Issue #28455: Merge from 3.6 files: Doc/library/argparse.rst | 9 +++++---- 1 files changed, 5 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 @@ -1958,10 +1958,11 @@ The method is called once per line read from the argument file, in order. A useful override of this method is one that treats each space-separated word - as an argument:: - - def convert_arg_line_to_args(self, arg_line): - return arg_line.split() + as an argument. The following example demonstrates how to do this:: + + class MyArgumentParser(argparse.ArgumentParser): + def convert_arg_line_to_args(self, arg_line): + return arg_line.split() Exiting methods -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Mon Oct 17 08:38:36 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 17 Oct 2016 13:38:36 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python 2.7 2016-10-17 Message-ID: <46af782f-1791-43ed-aff0-aa2cdbb8f543@irsmsx151.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-17 02:47:16 +0000 commit: 7dd0910e8fbf previous commit: 760403522d6b revision date: 2016-10-16 22:05:04 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% 1.87% 5.67% 2.69% :-) pybench 0.20% 0.01% 6.03% 4.38% :-( regex_v8 0.65% 0.03% -2.09% 10.71% :-) nbody 0.07% -0.05% 7.96% 5.17% :-) json_dump_v2 0.37% -0.17% 2.49% 8.69% :-| normal_startup 0.94% 0.42% -0.24% 2.02% :-| ssbench 0.25% -0.52% 1.64% 2.18% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-2-7-2016-10-17/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Mon Oct 17 08:56:09 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 17 Oct 2016 13:56:09 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-17 Message-ID: <8995e298-0bee-4854-88c0-d9becf0c361c@irsmsx151.ger.corp.intel.com> Results for project Python default, build date 2016-10-17 02:01:15 +0000 commit: b37db216c8e0 previous commit: 9513fac97ddd revision date: 2016-10-16 22:42:33 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.27% 0.67% 6.41% 13.12% :-) pybench 0.11% 0.14% 5.39% 5.22% :-( regex_v8 3.70% -0.29% -3.65% 3.76% :-) nbody 0.09% 1.22% 3.98% 1.34% :-( json_dump_v2 0.25% 0.72% -10.50% 16.48% :-| normal_startup 0.99% 0.07% 1.76% 6.26% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-17/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Mon Oct 17 12:15:30 2016 From: python-checkins at python.org (victor.stinner) Date: Mon, 17 Oct 2016 16:15:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E7=3A_Issue_=2328409=3A_regrtest=3A_fix_the_par?= =?utf-8?q?ser_of_command_line_arguments=2E?= Message-ID: <20161017161528.32822.91837.8ECC39CB@psf.io> https://hg.python.org/cpython/rev/9f03b3dbb929 changeset: 104523:9f03b3dbb929 parent: 104520:a293e5db9083 parent: 104522:26249f82c15d user: Victor Stinner date: Mon Oct 17 18:15:07 2016 +0200 summary: Merge 3.7: Issue #28409: regrtest: fix the parser of command line arguments. files: Lib/test/libregrtest/cmdline.py | 11 +++++++---- Lib/test/test_regrtest.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -242,9 +242,6 @@ group.add_argument('-P', '--pgo', dest='pgo', action='store_true', help='enable Profile Guided Optimization training') - parser.add_argument('args', nargs='*', - help=argparse.SUPPRESS) - return parser @@ -294,7 +291,13 @@ ns.use_resources = [] parser = _create_parser() - parser.parse_args(args=args, namespace=ns) + # Issue #14191: argparse doesn't support "intermixed" positional and + # optional arguments. Use parse_known_args() as workaround. + ns.args = parser.parse_known_args(args=args, namespace=ns)[1] + for arg in ns.args: + if arg.startswith('-'): + parser.error("unrecognized arguments: %s" % arg) + sys.exit(1) if ns.single and ns.fromfile: parser.error("-s and -f don't go together!") diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -299,6 +299,15 @@ self.assertEqual(ns.verbose, 0) self.assertEqual(ns.args, ['foo']) + def test_arg_option_arg(self): + ns = libregrtest._parse_args(['test_unaryop', '-v', 'test_binop']) + self.assertEqual(ns.verbose, 1) + self.assertEqual(ns.args, ['test_unaryop', 'test_binop']) + + def test_unknown_option(self): + self.checkError(['--unknown-option'], + 'unrecognized arguments: --unknown-option') + class BaseTestCase(unittest.TestCase): TEST_UNIQUE_ID = 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -312,6 +312,8 @@ Tests ----- +- Issue #28409: regrtest: fix the parser of command line arguments. + - Issue #28217: Adds _testconsole module to test console input. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 12:15:38 2016 From: python-checkins at python.org (victor.stinner) Date: Mon, 17 Oct 2016 16:15:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E6=3A_Issue_=2328409=3A_regrtest=3A_fix_the_parser_of?= =?utf-8?q?_command_line_arguments=2E?= Message-ID: <20161017161527.15457.70785.9804BC59@psf.io> https://hg.python.org/cpython/rev/26249f82c15d changeset: 104522:26249f82c15d branch: 3.6 parent: 104519:0b29adb5c804 parent: 104521:af06d9616c29 user: Victor Stinner date: Mon Oct 17 18:13:46 2016 +0200 summary: Merge 3.6: Issue #28409: regrtest: fix the parser of command line arguments. files: Lib/test/libregrtest/cmdline.py | 11 +++++++---- Lib/test/test_regrtest.py | 9 +++++++++ Misc/NEWS | 5 +++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -242,9 +242,6 @@ group.add_argument('-P', '--pgo', dest='pgo', action='store_true', help='enable Profile Guided Optimization training') - parser.add_argument('args', nargs='*', - help=argparse.SUPPRESS) - return parser @@ -294,7 +291,13 @@ ns.use_resources = [] parser = _create_parser() - parser.parse_args(args=args, namespace=ns) + # Issue #14191: argparse doesn't support "intermixed" positional and + # optional arguments. Use parse_known_args() as workaround. + ns.args = parser.parse_known_args(args=args, namespace=ns)[1] + for arg in ns.args: + if arg.startswith('-'): + parser.error("unrecognized arguments: %s" % arg) + sys.exit(1) if ns.single and ns.fromfile: parser.error("-s and -f don't go together!") diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -299,6 +299,15 @@ self.assertEqual(ns.verbose, 0) self.assertEqual(ns.args, ['foo']) + def test_arg_option_arg(self): + ns = libregrtest._parse_args(['test_unaryop', '-v', 'test_binop']) + self.assertEqual(ns.verbose, 1) + self.assertEqual(ns.args, ['test_unaryop', 'test_binop']) + + def test_unknown_option(self): + self.checkError(['--unknown-option'], + 'unrecognized arguments: --unknown-option') + class BaseTestCase(unittest.TestCase): TEST_UNIQUE_ID = 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,11 @@ - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. +Tests +----- + +- Issue #28409: regrtest: fix the parser of command line arguments. + What's New in Python 3.6.0 beta 2 ================================= -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 12:15:38 2016 From: python-checkins at python.org (victor.stinner) Date: Mon, 17 Oct 2016 16:15:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDA5?= =?utf-8?q?=3A_regrtest=3A_fix_the_parser_of_command_line_arguments=2E?= Message-ID: <20161017161527.15228.75060.A64CDCAC@psf.io> https://hg.python.org/cpython/rev/af06d9616c29 changeset: 104521:af06d9616c29 branch: 3.5 parent: 104518:4f8f7403881f user: Victor Stinner date: Mon Oct 17 18:11:03 2016 +0200 summary: Issue #28409: regrtest: fix the parser of command line arguments. files: Lib/test/regrtest.py | 11 +++++++---- Lib/test/test_regrtest.py | 10 ++++++++++ Misc/NEWS | 6 ++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -325,9 +325,6 @@ group.add_argument('-P', '--pgo', dest='pgo', action='store_true', help='enable Profile Guided Optimization training') - parser.add_argument('args', nargs='*', - help=argparse.SUPPRESS) - return parser def relative_filename(string): @@ -373,7 +370,13 @@ ns.use_resources = [] parser = _create_parser() - parser.parse_args(args=args, namespace=ns) + # Issue #14191: argparse doesn't support "intermixed" positional and + # optional arguments. Use parse_known_args() as workaround. + ns.args = parser.parse_known_args(args=args, namespace=ns)[1] + for arg in ns.args: + if arg.startswith('-'): + parser.error("unrecognized arguments: %s" % arg) + sys.exit(1) if ns.single and ns.fromfile: parser.error("-s and -f don't go together!") diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -270,6 +270,16 @@ self.assertEqual(ns.verbose, 0) self.assertEqual(ns.args, ['foo']) + def test_arg_option_arg(self): + ns = regrtest._parse_args(['test_unaryop', '-v', 'test_binop']) + self.assertEqual(ns.verbose, 1) + self.assertEqual(ns.args, ['test_unaryop', 'test_binop']) + + def test_unknown_option(self): + self.checkError(['--unknown-option'], + 'unrecognized arguments: --unknown-option') + + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -376,11 +376,11 @@ - Issue #27759: Fix selectors incorrectly retain invalid file descriptors. Patch by Mark Williams. -- Issue #28368: Refuse monitoring processes if the child watcher has +- Issue #28368: Refuse monitoring processes if the child watcher has no loop attached. Patch by Vincent Michel. -- Issue #28369: Raise RuntimeError when transport's FD is used with +- Issue #28369: Raise RuntimeError when transport's FD is used with add_reader, add_writer, etc. - Issue #28370: Speedup asyncio.StreamReader.readexactly. @@ -432,6 +432,8 @@ Tests ----- +- Issue #28409: regrtest: fix the parser of command line arguments. + - Issue #27787: Call gc.collect() before checking each test for "dangling threads", since the dangling threads are weak references. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 17:34:47 2016 From: python-checkins at python.org (berker.peksag) Date: Mon, 17 Oct 2016 21:34:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_from_3=2E6?= Message-ID: <20161017213447.15271.76529.F0F026E8@psf.io> https://hg.python.org/cpython/rev/3a58b70345e3 changeset: 104526:3a58b70345e3 parent: 104523:9f03b3dbb929 parent: 104525:7527ce67a3b1 user: Berker Peksag date: Tue Oct 18 00:35:31 2016 +0300 summary: Merge from 3.6 files: Doc/library/asyncio-stream.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -142,7 +142,7 @@ This method is a :ref:`coroutine `. - .. coroutinemethod:: readuntil(separator=b'\n') + .. coroutinemethod:: readuntil(separator=b'\\n') Read data from the stream until ``separator`` is found. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 17:34:47 2016 From: python-checkins at python.org (berker.peksag) Date: Mon, 17 Oct 2016 21:34:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fix_default_va?= =?utf-8?q?lue_of_StreamReader=2Ereaduntil=28=29?= Message-ID: <20161017213447.1506.31654.3E69310F@psf.io> https://hg.python.org/cpython/rev/14363cf42e15 changeset: 104524:14363cf42e15 branch: 3.5 parent: 104521:af06d9616c29 user: Berker Peksag date: Tue Oct 18 00:34:46 2016 +0300 summary: Fix default value of StreamReader.readuntil() Reported by Sam Lunt on docs at p.o. files: Doc/library/asyncio-stream.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -142,7 +142,7 @@ This method is a :ref:`coroutine `. - .. coroutinemethod:: readuntil(separator=b'\n') + .. coroutinemethod:: readuntil(separator=b'\\n') Read data from the stream until ``separator`` is found. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 17:34:47 2016 From: python-checkins at python.org (berker.peksag) Date: Mon, 17 Oct 2016 21:34:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5?= Message-ID: <20161017213447.32822.32836.E5F6BE28@psf.io> https://hg.python.org/cpython/rev/7527ce67a3b1 changeset: 104525:7527ce67a3b1 branch: 3.6 parent: 104522:26249f82c15d parent: 104524:14363cf42e15 user: Berker Peksag date: Tue Oct 18 00:35:09 2016 +0300 summary: Merge from 3.5 files: Doc/library/asyncio-stream.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -142,7 +142,7 @@ This method is a :ref:`coroutine `. - .. coroutinemethod:: readuntil(separator=b'\n') + .. coroutinemethod:: readuntil(separator=b'\\n') Read data from the stream until ``separator`` is found. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 22:48:47 2016 From: python-checkins at python.org (inada.naoki) Date: Tue, 18 Oct 2016 02:48:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDUy?= =?utf-8?q?=3A_Remove_=5Fasyncio=2E=5Finit=5Fmodule_function?= Message-ID: <20161018024847.16949.96130.8F1B2B4B@psf.io> https://hg.python.org/cpython/rev/d32ec6591c49 changeset: 104527:d32ec6591c49 branch: 3.6 parent: 104525:7527ce67a3b1 user: INADA Naoki date: Tue Oct 18 11:48:14 2016 +0900 summary: Issue #28452: Remove _asyncio._init_module function files: Lib/asyncio/futures.py | 23 +--- Modules/_asynciomodule.c | 123 ++++++++++++-------------- 2 files changed, 64 insertions(+), 82 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -431,21 +431,6 @@ dest.set_result(result) -try: - import _asyncio -except ImportError: - pass -else: - _asyncio._init_module( - traceback.extract_stack, - events.get_event_loop, - _future_repr_info, - InvalidStateError, - CancelledError) - - Future = _asyncio.Future - - def _chain_future(source, destination): """Chain two futures so that when one completes, so does the other. @@ -496,3 +481,11 @@ new_future = loop.create_future() _chain_future(future, new_future) return new_future + + +try: + import _asyncio +except ImportError: + pass +else: + Future = _asyncio.Future diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -7,7 +7,6 @@ /* State of the _asyncio module */ -static int _asynciomod_ready; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; static PyObject *asyncio_repr_info_func; @@ -19,19 +18,6 @@ static PyObject* new_future_iter(PyObject *fut); -/* make sure module state is initialized and ready to be used. */ -static int -_AsyncioMod_EnsureState(void) -{ - if (!_asynciomod_ready) { - PyErr_SetString(PyExc_RuntimeError, - "_asyncio module wasn't properly initialized"); - return -1; - } - return 0; -} - - typedef enum { STATE_PENDING, STATE_CANCELLED, @@ -108,10 +94,6 @@ PyObject *res = NULL; _Py_IDENTIFIER(get_debug); - if (_AsyncioMod_EnsureState()) { - return -1; - } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { return -1; } @@ -218,10 +200,6 @@ static PyObject * FutureObj_exception(FutureObj *fut, PyObject *arg) { - if (_AsyncioMod_EnsureState()) { - return NULL; - } - if (fut->fut_state == STATE_CANCELLED) { PyErr_SetString(asyncio_CancelledError, ""); return NULL; @@ -251,10 +229,6 @@ static PyObject * FutureObj_set_result(FutureObj *fut, PyObject *res) { - if (_AsyncioMod_EnsureState()) { - return NULL; - } - if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); return NULL; @@ -282,10 +256,6 @@ { PyObject *exc_val = NULL; - if (_AsyncioMod_EnsureState()) { - return NULL; - } - if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); return NULL; @@ -949,59 +919,75 @@ /*********************** Module **************************/ -PyDoc_STRVAR(module_doc, "asyncio speedups.\n"); +static int +init_module(void) +{ + PyObject *module = NULL; -PyObject * -_init_module(PyObject *self, PyObject *args) -{ - PyObject *extract_stack; - PyObject *get_event_loop; - PyObject *repr_info_func; - PyObject *invalidStateError; - PyObject *cancelledError; + module = PyImport_ImportModule("traceback"); + if (module == NULL) { + return -1; + } + // new reference + traceback_extract_stack = PyObject_GetAttrString(module, "extract_stack"); + if (traceback_extract_stack == NULL) { + goto fail; + } + Py_DECREF(module); - if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, - &extract_stack, - &get_event_loop, - &repr_info_func, - &invalidStateError, - &cancelledError)) { - return NULL; + module = PyImport_ImportModule("asyncio.events"); + if (module == NULL) { + goto fail; + } + asyncio_get_event_loop = PyObject_GetAttrString(module, "get_event_loop"); + if (asyncio_get_event_loop == NULL) { + goto fail; + } + Py_DECREF(module); + + module = PyImport_ImportModule("asyncio.futures"); + if (module == NULL) { + goto fail; + } + asyncio_repr_info_func = PyObject_GetAttrString(module, + "_future_repr_info"); + if (asyncio_repr_info_func == NULL) { + goto fail; } - Py_INCREF(extract_stack); - Py_XSETREF(traceback_extract_stack, extract_stack); + asyncio_InvalidStateError = PyObject_GetAttrString(module, + "InvalidStateError"); + if (asyncio_InvalidStateError == NULL) { + goto fail; + } - Py_INCREF(get_event_loop); - Py_XSETREF(asyncio_get_event_loop, get_event_loop); + asyncio_CancelledError = PyObject_GetAttrString(module, "CancelledError"); + if (asyncio_CancelledError == NULL) { + goto fail; + } - Py_INCREF(repr_info_func); - Py_XSETREF(asyncio_repr_info_func, repr_info_func); + Py_DECREF(module); + return 0; - Py_INCREF(invalidStateError); - Py_XSETREF(asyncio_InvalidStateError, invalidStateError); - - Py_INCREF(cancelledError); - Py_XSETREF(asyncio_CancelledError, cancelledError); - - _asynciomod_ready = 1; - - Py_RETURN_NONE; +fail: + Py_CLEAR(traceback_extract_stack); + Py_CLEAR(asyncio_get_event_loop); + Py_CLEAR(asyncio_repr_info_func); + Py_CLEAR(asyncio_InvalidStateError); + Py_CLEAR(asyncio_CancelledError); + Py_CLEAR(module); + return -1; } -static struct PyMethodDef asynciomod_methods[] = { - {"_init_module", _init_module, METH_VARARGS, NULL}, - {NULL, NULL} -}; - +PyDoc_STRVAR(module_doc, "Accelerator module for asyncio"); static struct PyModuleDef _asynciomodule = { PyModuleDef_HEAD_INIT, /* m_base */ "_asyncio", /* m_name */ module_doc, /* m_doc */ -1, /* m_size */ - asynciomod_methods, /* m_methods */ + NULL, /* m_methods */ NULL, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ @@ -1012,6 +998,9 @@ PyMODINIT_FUNC PyInit__asyncio(void) { + if (init_module() < 0) { + return NULL; + } if (PyType_Ready(&FutureType) < 0) { return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 17 22:48:48 2016 From: python-checkins at python.org (inada.naoki) Date: Tue, 18 Oct 2016 02:48:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328452=3A_Remove_=5Fasyncio=2E=5Finit=5Fmodule_f?= =?utf-8?q?unction?= Message-ID: <20161018024847.18258.60521.9BF33ACA@psf.io> https://hg.python.org/cpython/rev/ce85a1f129e3 changeset: 104528:ce85a1f129e3 parent: 104526:3a58b70345e3 parent: 104527:d32ec6591c49 user: INADA Naoki date: Tue Oct 18 11:48:35 2016 +0900 summary: Issue #28452: Remove _asyncio._init_module function files: Lib/asyncio/futures.py | 23 +--- Modules/_asynciomodule.c | 123 ++++++++++++-------------- 2 files changed, 64 insertions(+), 82 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -431,21 +431,6 @@ dest.set_result(result) -try: - import _asyncio -except ImportError: - pass -else: - _asyncio._init_module( - traceback.extract_stack, - events.get_event_loop, - _future_repr_info, - InvalidStateError, - CancelledError) - - Future = _asyncio.Future - - def _chain_future(source, destination): """Chain two futures so that when one completes, so does the other. @@ -496,3 +481,11 @@ new_future = loop.create_future() _chain_future(future, new_future) return new_future + + +try: + import _asyncio +except ImportError: + pass +else: + Future = _asyncio.Future diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -7,7 +7,6 @@ /* State of the _asyncio module */ -static int _asynciomod_ready; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; static PyObject *asyncio_repr_info_func; @@ -19,19 +18,6 @@ static PyObject* new_future_iter(PyObject *fut); -/* make sure module state is initialized and ready to be used. */ -static int -_AsyncioMod_EnsureState(void) -{ - if (!_asynciomod_ready) { - PyErr_SetString(PyExc_RuntimeError, - "_asyncio module wasn't properly initialized"); - return -1; - } - return 0; -} - - typedef enum { STATE_PENDING, STATE_CANCELLED, @@ -108,10 +94,6 @@ PyObject *res = NULL; _Py_IDENTIFIER(get_debug); - if (_AsyncioMod_EnsureState()) { - return -1; - } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { return -1; } @@ -218,10 +200,6 @@ static PyObject * FutureObj_exception(FutureObj *fut, PyObject *arg) { - if (_AsyncioMod_EnsureState()) { - return NULL; - } - if (fut->fut_state == STATE_CANCELLED) { PyErr_SetString(asyncio_CancelledError, ""); return NULL; @@ -251,10 +229,6 @@ static PyObject * FutureObj_set_result(FutureObj *fut, PyObject *res) { - if (_AsyncioMod_EnsureState()) { - return NULL; - } - if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); return NULL; @@ -282,10 +256,6 @@ { PyObject *exc_val = NULL; - if (_AsyncioMod_EnsureState()) { - return NULL; - } - if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); return NULL; @@ -949,59 +919,75 @@ /*********************** Module **************************/ -PyDoc_STRVAR(module_doc, "asyncio speedups.\n"); +static int +init_module(void) +{ + PyObject *module = NULL; -PyObject * -_init_module(PyObject *self, PyObject *args) -{ - PyObject *extract_stack; - PyObject *get_event_loop; - PyObject *repr_info_func; - PyObject *invalidStateError; - PyObject *cancelledError; + module = PyImport_ImportModule("traceback"); + if (module == NULL) { + return -1; + } + // new reference + traceback_extract_stack = PyObject_GetAttrString(module, "extract_stack"); + if (traceback_extract_stack == NULL) { + goto fail; + } + Py_DECREF(module); - if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, - &extract_stack, - &get_event_loop, - &repr_info_func, - &invalidStateError, - &cancelledError)) { - return NULL; + module = PyImport_ImportModule("asyncio.events"); + if (module == NULL) { + goto fail; + } + asyncio_get_event_loop = PyObject_GetAttrString(module, "get_event_loop"); + if (asyncio_get_event_loop == NULL) { + goto fail; + } + Py_DECREF(module); + + module = PyImport_ImportModule("asyncio.futures"); + if (module == NULL) { + goto fail; + } + asyncio_repr_info_func = PyObject_GetAttrString(module, + "_future_repr_info"); + if (asyncio_repr_info_func == NULL) { + goto fail; } - Py_INCREF(extract_stack); - Py_XSETREF(traceback_extract_stack, extract_stack); + asyncio_InvalidStateError = PyObject_GetAttrString(module, + "InvalidStateError"); + if (asyncio_InvalidStateError == NULL) { + goto fail; + } - Py_INCREF(get_event_loop); - Py_XSETREF(asyncio_get_event_loop, get_event_loop); + asyncio_CancelledError = PyObject_GetAttrString(module, "CancelledError"); + if (asyncio_CancelledError == NULL) { + goto fail; + } - Py_INCREF(repr_info_func); - Py_XSETREF(asyncio_repr_info_func, repr_info_func); + Py_DECREF(module); + return 0; - Py_INCREF(invalidStateError); - Py_XSETREF(asyncio_InvalidStateError, invalidStateError); - - Py_INCREF(cancelledError); - Py_XSETREF(asyncio_CancelledError, cancelledError); - - _asynciomod_ready = 1; - - Py_RETURN_NONE; +fail: + Py_CLEAR(traceback_extract_stack); + Py_CLEAR(asyncio_get_event_loop); + Py_CLEAR(asyncio_repr_info_func); + Py_CLEAR(asyncio_InvalidStateError); + Py_CLEAR(asyncio_CancelledError); + Py_CLEAR(module); + return -1; } -static struct PyMethodDef asynciomod_methods[] = { - {"_init_module", _init_module, METH_VARARGS, NULL}, - {NULL, NULL} -}; - +PyDoc_STRVAR(module_doc, "Accelerator module for asyncio"); static struct PyModuleDef _asynciomodule = { PyModuleDef_HEAD_INIT, /* m_base */ "_asyncio", /* m_name */ module_doc, /* m_doc */ -1, /* m_size */ - asynciomod_methods, /* m_methods */ + NULL, /* m_methods */ NULL, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ @@ -1012,6 +998,9 @@ PyMODINIT_FUNC PyInit__asyncio(void) { + if (init_module() < 0) { + return NULL; + } if (PyType_Ready(&FutureType) < 0) { return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 06:28:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Oct 2016 10:28:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2323782=3A_Fixed_possible_memory_leak_in_=5FPyTraceback?= =?utf-8?q?=5FAdd=28=29_and_exception?= Message-ID: <20161018102834.12091.65032.FEA6319A@psf.io> https://hg.python.org/cpython/rev/2d352bf2b228 changeset: 104530:2d352bf2b228 branch: 3.6 parent: 104527:d32ec6591c49 parent: 104529:6b3be9f38f2a user: Serhiy Storchaka date: Tue Oct 18 13:26:25 2016 +0300 summary: Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). files: Misc/NEWS | 3 ++ Python/traceback.c | 46 +++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception + loss in PyTraceBack_Here(). + Library ------- diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -132,47 +132,53 @@ int PyTraceBack_Here(PyFrameObject *frame) { - PyThreadState *tstate = PyThreadState_GET(); - PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback; - PyTracebackObject *tb = newtracebackobject(oldtb, frame); - if (tb == NULL) + PyObject *exc, *val, *tb, *newtb; + PyErr_Fetch(&exc, &val, &tb); + newtb = (PyObject *)newtracebackobject((PyTracebackObject *)tb, frame); + if (newtb == NULL) { + _PyErr_ChainExceptions(exc, val, tb); return -1; - tstate->curexc_traceback = (PyObject *)tb; - Py_XDECREF(oldtb); + } + PyErr_Restore(exc, val, newtb); + Py_XDECREF(tb); return 0; } /* Insert a frame into the traceback for (funcname, filename, lineno). */ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno) { - PyObject *globals = NULL; - PyCodeObject *code = NULL; - PyFrameObject *frame = NULL; - PyObject *exception, *value, *tb; + PyObject *globals; + PyCodeObject *code; + PyFrameObject *frame; + PyObject *exc, *val, *tb; /* Save and clear the current exception. Python functions must not be called with an exception set. Calling Python functions happens when the codec of the filesystem encoding is implemented in pure Python. */ - PyErr_Fetch(&exception, &value, &tb); + PyErr_Fetch(&exc, &val, &tb); globals = PyDict_New(); if (!globals) - goto done; + goto error; code = PyCode_NewEmpty(filename, funcname, lineno); - if (!code) - goto done; + if (!code) { + Py_DECREF(globals); + goto error; + } frame = PyFrame_New(PyThreadState_Get(), code, globals, NULL); + Py_DECREF(globals); + Py_DECREF(code); if (!frame) - goto done; + goto error; frame->f_lineno = lineno; - PyErr_Restore(exception, value, tb); + PyErr_Restore(exc, val, tb); PyTraceBack_Here(frame); + Py_DECREF(frame); + return; -done: - Py_XDECREF(globals); - Py_XDECREF(code); - Py_XDECREF(frame); +error: + _PyErr_ChainExceptions(exc, val, tb); } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 06:28:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Oct 2016 10:28:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIzNzgy?= =?utf-8?q?=3A_Fixed_possible_memory_leak_in_=5FPyTraceback=5FAdd=28=29_an?= =?utf-8?q?d_exception?= Message-ID: <20161018102834.27181.50602.B166ECE7@psf.io> https://hg.python.org/cpython/rev/6b3be9f38f2a changeset: 104529:6b3be9f38f2a branch: 3.5 parent: 104524:14363cf42e15 user: Serhiy Storchaka date: Tue Oct 18 13:23:18 2016 +0300 summary: Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). files: Misc/NEWS | 3 ++ Python/traceback.c | 46 +++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception + loss in PyTraceBack_Here(). + - Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). Patch by Xiang Zhang. diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -132,47 +132,53 @@ int PyTraceBack_Here(PyFrameObject *frame) { - PyThreadState *tstate = PyThreadState_GET(); - PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback; - PyTracebackObject *tb = newtracebackobject(oldtb, frame); - if (tb == NULL) + PyObject *exc, *val, *tb, *newtb; + PyErr_Fetch(&exc, &val, &tb); + newtb = (PyObject *)newtracebackobject((PyTracebackObject *)tb, frame); + if (newtb == NULL) { + _PyErr_ChainExceptions(exc, val, tb); return -1; - tstate->curexc_traceback = (PyObject *)tb; - Py_XDECREF(oldtb); + } + PyErr_Restore(exc, val, newtb); + Py_XDECREF(tb); return 0; } /* Insert a frame into the traceback for (funcname, filename, lineno). */ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno) { - PyObject *globals = NULL; - PyCodeObject *code = NULL; - PyFrameObject *frame = NULL; - PyObject *exception, *value, *tb; + PyObject *globals; + PyCodeObject *code; + PyFrameObject *frame; + PyObject *exc, *val, *tb; /* Save and clear the current exception. Python functions must not be called with an exception set. Calling Python functions happens when the codec of the filesystem encoding is implemented in pure Python. */ - PyErr_Fetch(&exception, &value, &tb); + PyErr_Fetch(&exc, &val, &tb); globals = PyDict_New(); if (!globals) - goto done; + goto error; code = PyCode_NewEmpty(filename, funcname, lineno); - if (!code) - goto done; + if (!code) { + Py_DECREF(globals); + goto error; + } frame = PyFrame_New(PyThreadState_Get(), code, globals, NULL); + Py_DECREF(globals); + Py_DECREF(code); if (!frame) - goto done; + goto error; frame->f_lineno = lineno; - PyErr_Restore(exception, value, tb); + PyErr_Restore(exc, val, tb); PyTraceBack_Here(frame); + Py_DECREF(frame); + return; -done: - Py_XDECREF(globals); - Py_XDECREF(code); - Py_XDECREF(frame); +error: + _PyErr_ChainExceptions(exc, val, tb); } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 06:28:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Oct 2016 10:28:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323782=3A_Fixed_possible_memory_leak_in_=5FPyTra?= =?utf-8?q?ceback=5FAdd=28=29_and_exception?= Message-ID: <20161018102835.68467.96546.D56A1413@psf.io> https://hg.python.org/cpython/rev/83877018ef97 changeset: 104531:83877018ef97 parent: 104528:ce85a1f129e3 parent: 104530:2d352bf2b228 user: Serhiy Storchaka date: Tue Oct 18 13:27:54 2016 +0300 summary: Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). files: Misc/NEWS | 3 ++ Python/traceback.c | 46 +++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception + loss in PyTraceBack_Here(). + - Issue #28183: Optimize and cleanup dict iteration. - Issue #26081: Added C implementation of asyncio.Future. diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -132,47 +132,53 @@ int PyTraceBack_Here(PyFrameObject *frame) { - PyThreadState *tstate = PyThreadState_GET(); - PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback; - PyTracebackObject *tb = newtracebackobject(oldtb, frame); - if (tb == NULL) + PyObject *exc, *val, *tb, *newtb; + PyErr_Fetch(&exc, &val, &tb); + newtb = (PyObject *)newtracebackobject((PyTracebackObject *)tb, frame); + if (newtb == NULL) { + _PyErr_ChainExceptions(exc, val, tb); return -1; - tstate->curexc_traceback = (PyObject *)tb; - Py_XDECREF(oldtb); + } + PyErr_Restore(exc, val, newtb); + Py_XDECREF(tb); return 0; } /* Insert a frame into the traceback for (funcname, filename, lineno). */ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno) { - PyObject *globals = NULL; - PyCodeObject *code = NULL; - PyFrameObject *frame = NULL; - PyObject *exception, *value, *tb; + PyObject *globals; + PyCodeObject *code; + PyFrameObject *frame; + PyObject *exc, *val, *tb; /* Save and clear the current exception. Python functions must not be called with an exception set. Calling Python functions happens when the codec of the filesystem encoding is implemented in pure Python. */ - PyErr_Fetch(&exception, &value, &tb); + PyErr_Fetch(&exc, &val, &tb); globals = PyDict_New(); if (!globals) - goto done; + goto error; code = PyCode_NewEmpty(filename, funcname, lineno); - if (!code) - goto done; + if (!code) { + Py_DECREF(globals); + goto error; + } frame = PyFrame_New(PyThreadState_Get(), code, globals, NULL); + Py_DECREF(globals); + Py_DECREF(code); if (!frame) - goto done; + goto error; frame->f_lineno = lineno; - PyErr_Restore(exception, value, tb); + PyErr_Restore(exc, val, tb); PyTraceBack_Here(frame); + Py_DECREF(frame); + return; -done: - Py_XDECREF(globals); - Py_XDECREF(code); - Py_XDECREF(frame); +error: + _PyErr_ChainExceptions(exc, val, tb); } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 09:49:01 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 13:49:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge_3=2E6_=28change_already_applied_in_default=29?= Message-ID: <20161018134900.38738.5159.8DE87C4C@psf.io> https://hg.python.org/cpython/rev/69523a2327ec changeset: 104534:69523a2327ec parent: 104531:83877018ef97 parent: 104533:a218260334c4 user: Victor Stinner date: Tue Oct 18 15:48:27 2016 +0200 summary: Null merge 3.6 (change already applied in default) files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 09:49:01 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 13:49:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3ODk2?= =?utf-8?q?=3A_Allow_passing_sphinx_options_to_Doc/Makefile?= Message-ID: <20161018134859.11827.11773.8BF84BE0@psf.io> https://hg.python.org/cpython/rev/87aced4a9cf5 changeset: 104532:87aced4a9cf5 branch: 3.5 parent: 104529:6b3be9f38f2a user: Victor Stinner date: Sun Oct 16 19:14:23 2016 +0200 summary: Issue #27896: Allow passing sphinx options to Doc/Makefile Patch written by Julien Palard. files: Doc/Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -162,12 +162,12 @@ # for development releases: always build autobuild-dev: - make dist SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make dist SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' -make suspicious # for quick rebuilds (HTML only) autobuild-dev-html: - make html SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make html SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' # for stable releases: only build if not in pre-release stage (alpha, beta) # release candidate downloads are okay, since the stable tree can be in that stage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 09:49:01 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 13:49:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5?= Message-ID: <20161018134900.12226.87851.CA9110E3@psf.io> https://hg.python.org/cpython/rev/a218260334c4 changeset: 104533:a218260334c4 branch: 3.6 parent: 104530:2d352bf2b228 parent: 104532:87aced4a9cf5 user: Victor Stinner date: Tue Oct 18 15:48:14 2016 +0200 summary: Merge 3.5 files: Doc/Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -162,12 +162,12 @@ # for development releases: always build autobuild-dev: - make dist SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make dist SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' -make suspicious # for quick rebuilds (HTML only) autobuild-dev-html: - make html SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make html SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' # for stable releases: only build if not in pre-release stage (alpha, beta) # release candidate downloads are okay, since the stable tree can be in that stage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 09:49:20 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 13:49:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI3ODk2?= =?utf-8?q?=3A_Allow_passing_sphinx_options_to_Doc/Makefile?= Message-ID: <20161018134920.38632.26659.EF90635C@psf.io> https://hg.python.org/cpython/rev/3b22c99535d0 changeset: 104535:3b22c99535d0 branch: 2.7 parent: 104514:7dd0910e8fbf user: Victor Stinner date: Sun Oct 16 19:14:23 2016 +0200 summary: Issue #27896: Allow passing sphinx options to Doc/Makefile Patch written by Julien Palard. files: Doc/Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -157,12 +157,12 @@ # for development releases: always build autobuild-dev: - make dist SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make dist SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' -make suspicious # for quick rebuilds (HTML only) autobuild-dev-html: - make html SPHINXOPTS='-A daily=1 -A versionswitcher=1' + make html SPHINXOPTS='$(SPHINXOPTS) -A daily=1 -A versionswitcher=1' # for stable releases: only build if not in pre-release stage (alpha, beta) # release candidate downloads are okay, since the stable tree can be in that stage -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 10:32:49 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 14:32:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328256=3A_Cleanup_?= =?utf-8?q?=5Fmath=2Ec?= Message-ID: <20161018143203.25293.10746.1EE220F7@psf.io> https://hg.python.org/cpython/rev/8999d702ac29 changeset: 104536:8999d702ac29 parent: 104534:69523a2327ec user: Victor Stinner date: Tue Oct 18 16:29:27 2016 +0200 summary: Issue #28256: Cleanup _math.c Only define fallback implementations when needed. It avoids producing deadcode when the system provides required math functions. files: Modules/_math.c | 49 +++++++++++++++++++++--------------- Modules/_math.h | 24 +++++++++--------- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Modules/_math.c b/Modules/_math.c --- a/Modules/_math.c +++ b/Modules/_math.c @@ -19,13 +19,19 @@ * ==================================================== */ +#if !defined(HAVE_ACOSH) || !defined(HAVE_ASINH) static const double ln2 = 6.93147180559945286227E-01; +static const double two_pow_p28 = 268435456.0; /* 2**28 */ +#endif +#if !defined(HAVE_ASINH) || !defined(HAVE_ATANH) static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */ -static const double two_pow_p28 = 268435456.0; /* 2**28 */ -#ifndef Py_NAN +#endif +#if !defined(HAVE_ATANH) && !defined(Py_NAN) static const double zero = 0.0; #endif + +#ifndef HAVE_ACOSH /* acosh(x) * Method : * Based on @@ -59,23 +65,25 @@ return x+x; } else { - return log(x)+ln2; /* acosh(huge)=log(2x) */ + return log(x) + ln2; /* acosh(huge)=log(2x) */ } } else if (x == 1.) { return 0.0; /* acosh(1) = 0 */ } else if (x > 2.) { /* 2 < x < 2**28 */ - double t = x*x; - return log(2.0*x - 1.0 / (x + sqrt(t - 1.0))); + double t = x * x; + return log(2.0 * x - 1.0 / (x + sqrt(t - 1.0))); } else { /* 1 < x <= 2 */ double t = x - 1.0; - return m_log1p(t + sqrt(2.0*t + t*t)); + return m_log1p(t + sqrt(2.0 * t + t * t)); } } +#endif /* HAVE_ACOSH */ +#ifndef HAVE_ASINH /* asinh(x) * Method : * Based on @@ -100,10 +108,10 @@ return x; /* return x inexact except 0 */ } if (absx > two_pow_p28) { /* |x| > 2**28 */ - w = log(absx)+ln2; + w = log(absx) + ln2; } else if (absx > 2.0) { /* 2 < |x| < 2**28 */ - w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx)); + w = log(2.0 * absx + 1.0 / (sqrt(x * x + 1.0) + absx)); } else { /* 2**-28 <= |x| < 2= */ double t = x*x; @@ -112,7 +120,10 @@ return copysign(w, x); } +#endif /* HAVE_ASINH */ + +#ifndef HAVE_ATANH /* atanh(x) * Method : * 1.Reduced x to positive by atanh(-x) = -atanh(x) @@ -145,7 +156,7 @@ #ifdef Py_NAN return Py_NAN; #else - return x/zero; + return x / zero; #endif } if (absx < two_pow_m28) { /* |x| < 2**-28 */ @@ -160,7 +171,10 @@ } return copysign(t, x); } +#endif /* HAVE_ATANH */ + +#ifndef HAVE_EXPM1 /* Mathematically, expm1(x) = exp(x) - 1. The expm1 function is designed to avoid the significant loss of precision that arises from direct evaluation of the expression exp(x) - 1, for x near 0. */ @@ -186,16 +200,17 @@ else return exp(x) - 1.0; } +#endif /* HAVE_EXPM1 */ + /* log1p(x) = log(1+x). The log1p function is designed to avoid the significant loss of precision that arises from direct evaluation when x is small. */ -#ifdef HAVE_LOG1P - double _Py_log1p(double x) { +#ifdef HAVE_LOG1P /* Some platforms supply a log1p function but don't respect the sign of zero: log1p(-0.0) gives 0.0 instead of the correct result of -0.0. @@ -208,13 +223,7 @@ else { return log1p(x); } -} - #else - -double -_Py_log1p(double x) -{ /* For x small, we use the following approach. Let y be the nearest float to 1+x, then @@ -236,7 +245,7 @@ */ double y; - if (fabs(x) < DBL_EPSILON/2.) { + if (fabs(x) < DBL_EPSILON / 2.) { return x; } else if (-0.5 <= x && x <= 1.) { @@ -246,12 +255,12 @@ happens, then results from log1p will be inaccurate for small x. */ y = 1.+x; - return log(y)-((y-1.)-x)/y; + return log(y) - ((y - 1.) - x) / y; } else { /* NaNs and infinities should end up here */ return log(1.+x); } +#endif /* ifdef HAVE_LOG1P */ } -#endif /* ifdef HAVE_LOG1P */ diff --git a/Modules/_math.h b/Modules/_math.h --- a/Modules/_math.h +++ b/Modules/_math.h @@ -1,41 +1,41 @@ -double _Py_acosh(double x); -double _Py_asinh(double x); -double _Py_atanh(double x); -double _Py_expm1(double x); -double _Py_log1p(double x); - #ifdef HAVE_ACOSH -#define m_acosh acosh +# define m_acosh acosh #else /* if the system doesn't have acosh, use the substitute function defined in Modules/_math.c. */ -#define m_acosh _Py_acosh +double _Py_acosh(double x); +# define m_acosh _Py_acosh #endif #ifdef HAVE_ASINH -#define m_asinh asinh +# define m_asinh asinh #else /* if the system doesn't have asinh, use the substitute function defined in Modules/_math.c. */ -#define m_asinh _Py_asinh +double _Py_asinh(double x); +# define m_asinh _Py_asinh #endif #ifdef HAVE_ATANH -#define m_atanh atanh +# define m_atanh atanh #else /* if the system doesn't have atanh, use the substitute function defined in Modules/_math.c. */ +double _Py_atanh(double x); #define m_atanh _Py_atanh #endif #ifdef HAVE_EXPM1 -#define m_expm1 expm1 +# define m_expm1 expm1 #else /* if the system doesn't have expm1, use the substitute function defined in Modules/_math.c. */ +double _Py_expm1(double x); #define m_expm1 _Py_expm1 #endif +double _Py_log1p(double x); + /* Use the substitute from _math.c on all platforms: it includes workarounds for buggy handling of zeros. */ #define m_log1p _Py_log1p -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 10:38:24 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 14:38:24 +0000 Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_benchmarks_is_deprecate?= =?utf-8?q?d=2C_please_use_performance?= Message-ID: <20161018143823.38960.42567.8C80C867@psf.io> https://hg.python.org/benchmarks/rev/198c43ca2f5b changeset: 240:198c43ca2f5b user: Victor Stinner date: Tue Oct 18 16:38:18 2016 +0200 summary: benchmarks is deprecated, please use performance files: README.txt | 32 ++++++++++++++++++++++++++++++++ perf.py | 15 ++++++++++++++- 2 files changed, 46 insertions(+), 1 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -1,3 +1,35 @@ ++++++++++++ +Deprecated! ++++++++++++ + +The old benchmarks project is now deprecated, please move to the new shiny +Python benchmark suite: + + https://github.com/python/performance + https://pypi.python.org/pypi/performance + + + + + + + + + + + + + + + + + + + + + + + The Grand Unified Python Benchmark Suite ######################################## diff --git a/perf.py b/perf.py --- a/perf.py +++ b/perf.py @@ -66,8 +66,9 @@ import subprocess import sys import tempfile +import textwrap +import threading import time -import threading try: import http.client as httpclient except: @@ -2543,6 +2544,18 @@ def main(argv, bench_funcs=BENCH_FUNCS, bench_groups=BENCH_GROUPS): + print(textwrap.dedent(''' + +++++++++++ + Deprecated! + +++++++++++ + + The old benchmarks project is now deprecated, please move + to the new shiny Python benchmark suite: + + https://github.com/python/performance + https://pypi.python.org/pypi/performance + + ''').lstrip()) bench_groups = CreateBenchGroups(bench_funcs, bench_groups) # Calculate the lengths of expanded benchmark names for all groups -- Repository URL: https://hg.python.org/benchmarks From lp_benchmark_robot at intel.com Tue Oct 18 10:43:35 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 18 Oct 2016 15:43:35 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python 2.7 2016-10-18 Message-ID: <2cc8e7cb-636c-40fc-88a5-dafa3dd4e645@irsmsx101.ger.corp.intel.com> No new revisions. Here are the previous results: Results for project Python 2.7, build date 2016-10-18 02:47:41 +0000 commit: 7dd0910e8fbf previous commit: 760403522d6b revision date: 2016-10-16 22:05:04 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% 1.87% 5.67% 2.69% :-) pybench 0.20% 0.01% 6.03% 4.38% :-( regex_v8 0.65% 0.03% -2.09% 10.71% :-) nbody 0.07% -0.05% 7.96% 5.17% :-) json_dump_v2 0.37% -0.17% 2.49% 8.69% :-| normal_startup 0.94% 0.42% -0.24% 2.02% :-| ssbench 0.25% -0.52% 1.64% 2.18% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-2-7-2016-10-18/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Tue Oct 18 10:44:56 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 18 Oct 2016 15:44:56 +0100 Subject: [Python-checkins] BAD Benchmark Results for Python Default 2016-10-18 Message-ID: <11859c4a-3ce4-47dc-9eac-c34ea33b7989@irsmsx101.ger.corp.intel.com> Results for project Python default, build date 2016-10-18 02:01:27 +0000 commit: 3a58b70345e3 previous commit: b37db216c8e0 revision date: 2016-10-17 21:35:31 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.30% -1.96% 4.58% 14.63% :-) pybench 0.18% -0.05% 5.34% 5.73% :-( regex_v8 3.70% -0.01% -3.65% 4.52% :-) nbody 0.09% -0.04% 3.94% 5.56% :-( json_dump_v2 0.37% -1.04% -11.64% 17.19% :-| normal_startup 0.69% -0.28% 1.67% 6.53% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/bad-benchmark-results-for-python-default-2016-10-18/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Tue Oct 18 11:14:49 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 15:14:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_timeit=3A_change_default_r?= =?utf-8?q?epeat_to_5=2C_instead_of_3?= Message-ID: <20161018151423.25195.82454.996C92AD@psf.io> https://hg.python.org/cpython/rev/2dafb2f3e7ff changeset: 104538:2dafb2f3e7ff user: Victor Stinner date: Tue Oct 18 17:13:22 2016 +0200 summary: timeit: change default repeat to 5, instead of 3 Issue #28240: timeit now repeats the benchmarks 5 times instead of only 3 to make benchmarks more reliable. files: Lib/test/test_timeit.py | 34 ++++++++++++++-------------- Lib/timeit.py | 2 +- Misc/NEWS | 3 ++ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -12,7 +12,7 @@ DEFAULT_NUMBER = 1000000 # timeit's default number of repetitions. -DEFAULT_REPEAT = 3 +DEFAULT_REPEAT = 5 # XXX: some tests are commented out that would improve the coverage but take a # long time to run because they test the default number of loops, which is @@ -226,7 +226,7 @@ t.print_exc(s) self.assert_exc_string(s.getvalue(), 'ZeroDivisionError') - MAIN_DEFAULT_OUTPUT = "1 loop, best of 3: 1 sec per loop\n" + MAIN_DEFAULT_OUTPUT = "1 loop, best of 5: 1 sec per loop\n" def run_main(self, seconds_per_increment=1.0, switches=None, timer=None): if timer is None: @@ -252,31 +252,31 @@ def test_main_seconds(self): s = self.run_main(seconds_per_increment=5.5) - self.assertEqual(s, "1 loop, best of 3: 5.5 sec per loop\n") + self.assertEqual(s, "1 loop, best of 5: 5.5 sec per loop\n") def test_main_milliseconds(self): s = self.run_main(seconds_per_increment=0.0055) - self.assertEqual(s, "100 loops, best of 3: 5.5 msec per loop\n") + self.assertEqual(s, "100 loops, best of 5: 5.5 msec per loop\n") def test_main_microseconds(self): s = self.run_main(seconds_per_increment=0.0000025, switches=['-n100']) - self.assertEqual(s, "100 loops, best of 3: 2.5 usec per loop\n") + self.assertEqual(s, "100 loops, best of 5: 2.5 usec per loop\n") def test_main_fixed_iters(self): s = self.run_main(seconds_per_increment=2.0, switches=['-n35']) - self.assertEqual(s, "35 loops, best of 3: 2 sec per loop\n") + self.assertEqual(s, "35 loops, best of 5: 2 sec per loop\n") def test_main_setup(self): s = self.run_main(seconds_per_increment=2.0, switches=['-n35', '-s', 'print("CustomSetup")']) - self.assertEqual(s, "CustomSetup\n" * 3 + - "35 loops, best of 3: 2 sec per loop\n") + self.assertEqual(s, "CustomSetup\n" * DEFAULT_REPEAT + + "35 loops, best of 5: 2 sec per loop\n") def test_main_multiple_setups(self): s = self.run_main(seconds_per_increment=2.0, switches=['-n35', '-s', 'a = "CustomSetup"', '-s', 'print(a)']) - self.assertEqual(s, "CustomSetup\n" * 3 + - "35 loops, best of 3: 2 sec per loop\n") + self.assertEqual(s, "CustomSetup\n" * DEFAULT_REPEAT + + "35 loops, best of 5: 2 sec per loop\n") def test_main_fixed_reps(self): s = self.run_main(seconds_per_increment=60.0, switches=['-r9']) @@ -309,8 +309,8 @@ s = self.run_main(switches=['-v']) self.assertEqual(s, dedent("""\ 1 loop -> 1 secs - raw times: 1 1 1 - 1 loop, best of 3: 1 sec per loop + raw times: 1 1 1 1 1 + 1 loop, best of 5: 1 sec per loop """)) def test_main_very_verbose(self): @@ -321,23 +321,23 @@ 100 loops -> 0.005 secs 1000 loops -> 0.05 secs 10000 loops -> 0.5 secs - raw times: 0.5 0.5 0.5 - 10000 loops, best of 3: 50 usec per loop + raw times: 0.5 0.5 0.5 0.5 0.5 + 10000 loops, best of 5: 50 usec per loop """)) def test_main_with_time_unit(self): unit_sec = self.run_main(seconds_per_increment=0.002, switches=['-u', 'sec']) self.assertEqual(unit_sec, - "100 loops, best of 3: 0.002 sec per loop\n") + "100 loops, best of 5: 0.002 sec per loop\n") unit_msec = self.run_main(seconds_per_increment=0.002, switches=['-u', 'msec']) self.assertEqual(unit_msec, - "100 loops, best of 3: 2 msec per loop\n") + "100 loops, best of 5: 2 msec per loop\n") unit_usec = self.run_main(seconds_per_increment=0.002, switches=['-u', 'usec']) self.assertEqual(unit_usec, - "100 loops, best of 3: 2e+03 usec per loop\n") + "100 loops, best of 5: 2e+03 usec per loop\n") # Test invalid unit input with captured_stderr() as error_stringio: invalid = self.run_main(seconds_per_increment=0.002, diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -59,7 +59,7 @@ dummy_src_name = "" default_number = 1000000 -default_repeat = 3 +default_repeat = 5 default_timer = time.perf_counter _globals = globals diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ Library ------- +- Issue #28240: timeit now repeats the benchmarks 5 times instead of only 3 + to make benchmarks more reliable. + - Issue #28240: timeit autorange now uses a single loop iteration if the benchmark takes less than 10 seconds, instead of 10 iterations. "python3 -m timeit -s 'import time' 'time.sleep(1)'" now takes 4 seconds -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 11:14:49 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 15:14:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_timeit=3A_start_autorange_?= =?utf-8?q?with_1_iteration=2C_not_10?= Message-ID: <20161018151423.18098.75625.9D9C2843@psf.io> https://hg.python.org/cpython/rev/3aba5552b976 changeset: 104537:3aba5552b976 user: Victor Stinner date: Tue Oct 18 17:06:56 2016 +0200 summary: timeit: start autorange with 1 iteration, not 10 Issue #28240: timeit autorange now uses a single loop iteration if the benchmark takes less than 10 seconds, instead of 10 iterations. "python3 -m timeit -s 'import time' 'time.sleep(1)'" now takes 4 seconds instead of 40 seconds. files: Lib/test/test_timeit.py | 35 +++++++++++++++++----------- Lib/timeit.py | 10 ++++--- Misc/NEWS | 5 ++++ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -226,7 +226,7 @@ t.print_exc(s) self.assert_exc_string(s.getvalue(), 'ZeroDivisionError') - MAIN_DEFAULT_OUTPUT = "10 loops, best of 3: 1 sec per loop\n" + MAIN_DEFAULT_OUTPUT = "1 loop, best of 3: 1 sec per loop\n" def run_main(self, seconds_per_increment=1.0, switches=None, timer=None): if timer is None: @@ -252,7 +252,7 @@ def test_main_seconds(self): s = self.run_main(seconds_per_increment=5.5) - self.assertEqual(s, "10 loops, best of 3: 5.5 sec per loop\n") + self.assertEqual(s, "1 loop, best of 3: 5.5 sec per loop\n") def test_main_milliseconds(self): s = self.run_main(seconds_per_increment=0.0055) @@ -280,11 +280,11 @@ def test_main_fixed_reps(self): s = self.run_main(seconds_per_increment=60.0, switches=['-r9']) - self.assertEqual(s, "10 loops, best of 9: 60 sec per loop\n") + self.assertEqual(s, "1 loop, best of 9: 60 sec per loop\n") def test_main_negative_reps(self): s = self.run_main(seconds_per_increment=60.0, switches=['-r-5']) - self.assertEqual(s, "10 loops, best of 1: 60 sec per loop\n") + self.assertEqual(s, "1 loop, best of 1: 60 sec per loop\n") @unittest.skipIf(sys.flags.optimize >= 2, "need __doc__") def test_main_help(self): @@ -308,14 +308,15 @@ def test_main_verbose(self): s = self.run_main(switches=['-v']) self.assertEqual(s, dedent("""\ - 10 loops -> 10 secs - raw times: 10 10 10 - 10 loops, best of 3: 1 sec per loop + 1 loop -> 1 secs + raw times: 1 1 1 + 1 loop, best of 3: 1 sec per loop """)) def test_main_very_verbose(self): s = self.run_main(seconds_per_increment=0.000050, switches=['-vv']) self.assertEqual(s, dedent("""\ + 1 loop -> 5e-05 secs 10 loops -> 0.0005 secs 100 loops -> 0.005 secs 1000 loops -> 0.05 secs @@ -328,15 +329,15 @@ unit_sec = self.run_main(seconds_per_increment=0.002, switches=['-u', 'sec']) self.assertEqual(unit_sec, - "1000 loops, best of 3: 0.002 sec per loop\n") + "100 loops, best of 3: 0.002 sec per loop\n") unit_msec = self.run_main(seconds_per_increment=0.002, switches=['-u', 'msec']) self.assertEqual(unit_msec, - "1000 loops, best of 3: 2 msec per loop\n") + "100 loops, best of 3: 2 msec per loop\n") unit_usec = self.run_main(seconds_per_increment=0.002, switches=['-u', 'usec']) self.assertEqual(unit_usec, - "1000 loops, best of 3: 2e+03 usec per loop\n") + "100 loops, best of 3: 2e+03 usec per loop\n") # Test invalid unit input with captured_stderr() as error_stringio: invalid = self.run_main(seconds_per_increment=0.002, @@ -354,8 +355,8 @@ s = self.run_main(switches=['-n1', '1/0']) self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError') - def autorange(self, callback=None): - timer = FakeTimer(seconds_per_increment=0.001) + def autorange(self, seconds_per_increment=0.001, callback=None): + timer = FakeTimer(seconds_per_increment=seconds_per_increment) t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer) return t.autorange(callback) @@ -364,14 +365,20 @@ self.assertEqual(num_loops, 1000) self.assertEqual(time_taken, 1.0) + def test_autorange_second(self): + num_loops, time_taken = self.autorange(seconds_per_increment=1.0) + self.assertEqual(num_loops, 1) + self.assertEqual(time_taken, 1.0) + def test_autorange_with_callback(self): def callback(a, b): print("{} {:.3f}".format(a, b)) with captured_stdout() as s: - num_loops, time_taken = self.autorange(callback) + num_loops, time_taken = self.autorange(callback=callback) self.assertEqual(num_loops, 1000) self.assertEqual(time_taken, 1.0) - expected = ('10 0.010\n' + expected = ('1 0.001\n' + '10 0.010\n' '100 0.100\n' '1000 1.000\n') self.assertEqual(s.getvalue(), expected) diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -218,7 +218,7 @@ If *callback* is given and is not None, it will be called after each trial with two arguments: ``callback(number, time_taken)``. """ - for i in range(1, 10): + for i in range(0, 10): number = 10**i time_taken = self.timeit(number) if callback: @@ -318,8 +318,10 @@ callback = None if verbose: def callback(number, time_taken): - msg = "{num} loops -> {secs:.{prec}g} secs" - print(msg.format(num=number, secs=time_taken, prec=precision)) + msg = "{num} loop{s} -> {secs:.{prec}g} secs" + plural = (number != 1) + print(msg.format(num=number, s='s' if plural else '', + secs=time_taken, prec=precision)) try: number, _ = t.autorange(callback) except: @@ -333,7 +335,7 @@ best = min(r) if verbose: print("raw times:", " ".join(["%.*g" % (precision, x) for x in r])) - print("%d loops," % number, end=' ') + print("%d loop%s," % (number, 's' if number != 1 else ''), end=' ') usec = best * 1e6 / number if time_unit is not None: scale = units[time_unit] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,11 @@ Library ------- +- Issue #28240: timeit autorange now uses a single loop iteration if the + benchmark takes less than 10 seconds, instead of 10 iterations. + "python3 -m timeit -s 'import time' 'time.sleep(1)'" now takes 4 seconds + instead of 40 seconds. + - Distutils.sdist now looks for README and setup.py files with case sensitivity. This behavior matches that found in Setuptools 6.0 and later. See `setuptools 100 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 11:20:58 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 15:20:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_timeit=3A_remove_--clock_a?= =?utf-8?q?nd_--time_options?= Message-ID: <20161018152048.27249.84939.37E3292C@psf.io> https://hg.python.org/cpython/rev/975df4c13db6 changeset: 104539:975df4c13db6 user: Victor Stinner date: Tue Oct 18 17:18:21 2016 +0200 summary: timeit: remove --clock and --time options Issue #28240: timeit: remove -c/--clock and -t/--time command line options which were deprecated since Python 3.3. files: Doc/library/timeit.rst | 10 +--------- Lib/test/test_timeit.py | 12 ------------ Lib/timeit.py | 8 +------- Misc/NEWS | 3 +++ 4 files changed, 5 insertions(+), 28 deletions(-) diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -197,7 +197,7 @@ When called as a program from the command line, the following form is used:: - python -m timeit [-n N] [-r N] [-u U] [-s S] [-t] [-c] [-h] [statement ...] + python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...] Where the following options are understood: @@ -222,20 +222,12 @@ .. versionadded:: 3.3 -.. cmdoption:: -t, --time - - use :func:`time.time` (deprecated) - .. cmdoption:: -u, --unit=U specify a time unit for timer output; can select usec, msec, or sec .. versionadded:: 3.5 -.. cmdoption:: -c, --clock - - use :func:`time.clock` (deprecated) - .. cmdoption:: -v, --verbose print raw timing results; repeat for more digits precision diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -293,18 +293,6 @@ # the help text, but since it's there, check for it. self.assertEqual(s, timeit.__doc__ + ' ') - def test_main_using_time(self): - fake_timer = FakeTimer() - s = self.run_main(switches=['-t'], timer=fake_timer) - self.assertEqual(s, self.MAIN_DEFAULT_OUTPUT) - self.assertIs(fake_timer.saved_timer, time.time) - - def test_main_using_clock(self): - fake_timer = FakeTimer() - s = self.run_main(switches=['-c'], timer=fake_timer) - self.assertEqual(s, self.MAIN_DEFAULT_OUTPUT) - self.assertIs(fake_timer.saved_timer, time.clock) - def test_main_verbose(self): s = self.run_main(switches=['-v']) self.assertEqual(s, dedent("""\ diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -9,7 +9,7 @@ Library usage: see the Timer class. Command line usage: - python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-p] [-h] [--] [statement] + python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [--] [statement] Options: -n/--number N: how many times to execute 'statement' (default: see below) @@ -17,8 +17,6 @@ -s/--setup S: statement to be executed once initially (default 'pass'). Execution time of this setup statement is NOT timed. -p/--process: use time.process_time() (default is time.perf_counter()) - -t/--time: use time.time() (deprecated) - -c/--clock: use time.clock() (deprecated) -v/--verbose: print raw timing results; repeat for more digits precision -u/--unit: set the output time unit (usec, msec, or sec) -h/--help: print this usage message and exit @@ -291,10 +289,6 @@ repeat = int(a) if repeat <= 0: repeat = 1 - if o in ("-t", "--time"): - timer = time.time - if o in ("-c", "--clock"): - timer = time.clock if o in ("-p", "--process"): timer = time.process_time if o in ("-v", "--verbose"): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ Library ------- +- Issue #28240: timeit: remove ``-c/--clock`` and ``-t/--time`` command line + options which were deprecated since Python 3.3. + - Issue #28240: timeit now repeats the benchmarks 5 times instead of only 3 to make benchmarks more reliable. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 11:59:33 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 15:59:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_timeit=3A_add_newlines_to_?= =?utf-8?q?output_for_readability?= Message-ID: <20161018155932.32838.76635.083629C0@psf.io> https://hg.python.org/cpython/rev/40e97c9dae7a changeset: 104542:40e97c9dae7a user: Victor Stinner date: Tue Oct 18 17:55:18 2016 +0200 summary: timeit: add newlines to output for readability Issue #28240. files: Lib/test/test_timeit.py | 4 ++++ Lib/timeit.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -297,7 +297,9 @@ s = self.run_main(switches=['-v']) self.assertEqual(s, dedent("""\ 1 loop -> 1 secs + raw times: 1 sec, 1 sec, 1 sec, 1 sec, 1 sec + 1 loop, best of 5: 1 sec per loop """)) @@ -309,7 +311,9 @@ 100 loops -> 0.005 secs 1000 loops -> 0.05 secs 10000 loops -> 0.5 secs + raw times: 500 msec, 500 msec, 500 msec, 500 msec, 500 msec + 10000 loops, best of 5: 50 usec per loop """)) diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -325,6 +325,9 @@ t.print_exc() return 1 + if verbose: + print() + try: raw_timings = t.repeat(repeat, number) except: @@ -347,7 +350,7 @@ if verbose: print("raw times: %s" % ", ".join(map(format_time, raw_timings))) - + print() timings = [dt / number for dt in raw_timings] best = min(timings) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 11:59:33 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 15:59:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_timeit=3A_enhance_format_o?= =?utf-8?q?f_raw_timings_=28in_verbose_mode=29?= Message-ID: <20161018155931.11996.95008.8A9030C7@psf.io> https://hg.python.org/cpython/rev/4d611957732b changeset: 104540:4d611957732b user: Victor Stinner date: Tue Oct 18 17:56:42 2016 +0200 summary: timeit: enhance format of raw timings (in verbose mode) Issue #28240. files: Lib/test/test_timeit.py | 4 +- Lib/timeit.py | 63 +++++++++++++++++----------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -297,7 +297,7 @@ s = self.run_main(switches=['-v']) self.assertEqual(s, dedent("""\ 1 loop -> 1 secs - raw times: 1 1 1 1 1 + raw times: 1 sec, 1 sec, 1 sec, 1 sec, 1 sec 1 loop, best of 5: 1 sec per loop """)) @@ -309,7 +309,7 @@ 100 loops -> 0.005 secs 1000 loops -> 0.05 secs 10000 loops -> 0.5 secs - raw times: 0.5 0.5 0.5 0.5 0.5 + raw times: 500 msec, 500 msec, 500 msec, 500 msec, 500 msec 10000 loops, best of 5: 50 usec per loop """)) diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -264,6 +264,7 @@ print(err) print("use -h/--help for command line help") return 2 + timer = default_timer stmt = "\n".join(args) or "pass" number = 0 # auto-determine @@ -271,7 +272,7 @@ repeat = default_repeat verbose = 0 time_unit = None - units = {"usec": 1, "msec": 1e3, "sec": 1e6} + units = {"usec": 1e-6, "msec": 1e-3, "sec": 1.0} precision = 3 for o, a in opts: if o in ("-n", "--number"): @@ -299,6 +300,7 @@ print(__doc__, end=' ') return 0 setup = "\n".join(setup) or "pass" + # Include the current directory, so that local imports work (sys.path # contains the directory of this script, rather than the current # directory) @@ -306,6 +308,7 @@ sys.path.insert(0, os.curdir) if _wrap_timer is not None: timer = _wrap_timer(timer) + t = Timer(stmt, setup, timer) if number == 0: # determine number so that 0.2 <= total time < 2.0 @@ -321,37 +324,47 @@ except: t.print_exc() return 1 + try: - r = t.repeat(repeat, number) + raw_timings = t.repeat(repeat, number) except: t.print_exc() return 1 - best = min(r) + + def format_time(dt): + unit = time_unit + + if unit is not None: + scale = units[unit] + else: + scales = [(scale, unit) for unit, scale in units.items()] + scales.sort(reverse=True) + for scale, unit in scales: + if dt >= scale: + break + + return "%.*g %s" % (precision, dt / scale, unit) + if verbose: - print("raw times:", " ".join(["%.*g" % (precision, x) for x in r])) - print("%d loop%s," % (number, 's' if number != 1 else ''), end=' ') - usec = best * 1e6 / number - if time_unit is not None: - scale = units[time_unit] - else: - scales = [(scale, unit) for unit, scale in units.items()] - scales.sort(reverse=True) - for scale, time_unit in scales: - if usec >= scale: - break - print("best of %d: %.*g %s per loop" % (repeat, precision, - usec/scale, time_unit)) - best = min(r) - usec = best * 1e6 / number - worst = max(r) + print("raw times: %s" % ", ".join(map(format_time, raw_timings))) + + timings = [dt / number for dt in raw_timings] + + best = min(timings) + print("%d loop%s, best of %d: %s per loop" + % (number, 's' if number != 1 else '', + repeat, format_time(best))) + + best = min(timings) + worst = max(timings) if worst >= best * 4: - usec = worst * 1e6 / number import warnings - warnings.warn_explicit( - "The test results are likely unreliable. The worst\n" - "time (%.*g %s) was more than four times slower than the best time." % - (precision, usec/scale, time_unit), - UserWarning, '', 0) + warnings.warn_explicit("The test results are likely unreliable. " + "The worst time (%s) was more than four times " + "slower than the best time (%s)." + % (precision, + format_time(worst), format_time(best)), + UserWarning, '', 0) return None if __name__ == "__main__": -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 12:00:13 2016 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Oct 2016 16:00:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_timeit=3A_add_nsec_=28nano?= =?utf-8?q?second=29_unit_for_format_timings?= Message-ID: <20161018155931.25155.74435.30875954@psf.io> https://hg.python.org/cpython/rev/c3a93069111d changeset: 104541:c3a93069111d user: Victor Stinner date: Tue Oct 18 17:42:48 2016 +0200 summary: timeit: add nsec (nanosecond) unit for format timings Issue #28240. files: Doc/library/timeit.rst | 2 +- Lib/test/test_timeit.py | 2 +- Lib/timeit.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -224,7 +224,7 @@ .. cmdoption:: -u, --unit=U - specify a time unit for timer output; can select usec, msec, or sec + specify a time unit for timer output; can select nsec, usec, msec, or sec .. versionadded:: 3.5 diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -331,7 +331,7 @@ invalid = self.run_main(seconds_per_increment=0.002, switches=['-u', 'parsec']) self.assertEqual(error_stringio.getvalue(), - "Unrecognized unit. Please select usec, msec, or sec.\n") + "Unrecognized unit. Please select nsec, usec, msec, or sec.\n") def test_main_exception(self): with captured_stderr() as error_stringio: diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -18,7 +18,7 @@ Execution time of this setup statement is NOT timed. -p/--process: use time.process_time() (default is time.perf_counter()) -v/--verbose: print raw timing results; repeat for more digits precision - -u/--unit: set the output time unit (usec, msec, or sec) + -u/--unit: set the output time unit (nsec, usec, msec, or sec) -h/--help: print this usage message and exit --: separate options from statement, use when statement starts with - statement: statement to be timed (default 'pass') @@ -272,7 +272,7 @@ repeat = default_repeat verbose = 0 time_unit = None - units = {"usec": 1e-6, "msec": 1e-3, "sec": 1.0} + units = {"nsec": 1e-9, "usec": 1e-6, "msec": 1e-3, "sec": 1.0} precision = 3 for o, a in opts: if o in ("-n", "--number"): @@ -283,7 +283,7 @@ if a in units: time_unit = a else: - print("Unrecognized unit. Please select usec, msec, or sec.", + print("Unrecognized unit. Please select nsec, usec, msec, or sec.", file=sys.stderr) return 2 if o in ("-r", "--repeat"): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 16:04:46 2016 From: python-checkins at python.org (yury.selivanov) Date: Tue, 18 Oct 2016 20:04:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDcx?= =?utf-8?q?=3A_Fix_crash_=28GIL_state_related=29_in_socket=2Esetblocking?= Message-ID: <20161018200445.38784.27492.802CFE51@psf.io> https://hg.python.org/cpython/rev/4b5b233d4c98 changeset: 104543:4b5b233d4c98 branch: 3.6 parent: 104533:a218260334c4 user: Yury Selivanov date: Tue Oct 18 16:03:52 2016 -0400 summary: Issue #28471: Fix crash (GIL state related) in socket.setblocking files: Lib/test/test_socket.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ Modules/socketmodule.c | 26 ++++++++++++++++---------- 3 files changed, 32 insertions(+), 10 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 @@ -4552,6 +4552,18 @@ self.assertTrue(issubclass(socket.gaierror, OSError)) self.assertTrue(issubclass(socket.timeout, OSError)) + def test_setblocking_invalidfd(self): + # Regression test for issue #28471 + + sock0 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + sock = socket.socket( + socket.AF_INET, socket.SOCK_STREAM, 0, sock0.fileno()) + sock0.close() + + with self.assertRaises(OSError): + sock.setblocking(False) + + @unittest.skipUnless(sys.platform == 'linux', 'Linux specific test') class TestLinuxAbstractNamespace(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). +- Issue #28471: Fix "Python memory allocator called without holding the GIL" + crash in socket.setblocking. + + Library ------- diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -622,6 +622,7 @@ static int internal_setblocking(PySocketSockObject *s, int block) { + int result = -1; #ifdef MS_WINDOWS u_long arg; #endif @@ -641,34 +642,39 @@ #if (defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO)) block = !block; if (ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block) == -1) - goto error; + goto done; #else delay_flag = fcntl(s->sock_fd, F_GETFL, 0); if (delay_flag == -1) - goto error; + goto done; if (block) new_delay_flag = delay_flag & (~O_NONBLOCK); else new_delay_flag = delay_flag | O_NONBLOCK; if (new_delay_flag != delay_flag) if (fcntl(s->sock_fd, F_SETFL, new_delay_flag) == -1) - goto error; + goto done; #endif #else /* MS_WINDOWS */ arg = !block; if (ioctlsocket(s->sock_fd, FIONBIO, &arg) != 0) - goto error; + goto done; #endif /* MS_WINDOWS */ + + result = 0; + + done: Py_END_ALLOW_THREADS - return 0; - error: + if (result) { #ifndef MS_WINDOWS - PyErr_SetFromErrno(PyExc_OSError); + PyErr_SetFromErrno(PyExc_OSError); #else - PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); -#endif - return -1; + PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); +#endif + } + + return result; } static int -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 18 16:04:57 2016 From: python-checkins at python.org (yury.selivanov) Date: Tue, 18 Oct 2016 20:04:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg0NzEp?= Message-ID: <20161018200445.27249.46141.4FBC487F@psf.io> https://hg.python.org/cpython/rev/554fb699af8c changeset: 104544:554fb699af8c parent: 104542:40e97c9dae7a parent: 104543:4b5b233d4c98 user: Yury Selivanov date: Tue Oct 18 16:04:40 2016 -0400 summary: Merge 3.6 (issue #28471) files: Lib/test/test_socket.py | 12 ++++++++++++ Modules/socketmodule.c | 26 ++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 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 @@ -4562,6 +4562,18 @@ self.assertTrue(issubclass(socket.gaierror, OSError)) self.assertTrue(issubclass(socket.timeout, OSError)) + def test_setblocking_invalidfd(self): + # Regression test for issue #28471 + + sock0 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + sock = socket.socket( + socket.AF_INET, socket.SOCK_STREAM, 0, sock0.fileno()) + sock0.close() + + with self.assertRaises(OSError): + sock.setblocking(False) + + @unittest.skipUnless(sys.platform == 'linux', 'Linux specific test') class TestLinuxAbstractNamespace(unittest.TestCase): diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -622,6 +622,7 @@ static int internal_setblocking(PySocketSockObject *s, int block) { + int result = -1; #ifdef MS_WINDOWS u_long arg; #endif @@ -641,34 +642,39 @@ #if (defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO)) block = !block; if (ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block) == -1) - goto error; + goto done; #else delay_flag = fcntl(s->sock_fd, F_GETFL, 0); if (delay_flag == -1) - goto error; + goto done; if (block) new_delay_flag = delay_flag & (~O_NONBLOCK); else new_delay_flag = delay_flag | O_NONBLOCK; if (new_delay_flag != delay_flag) if (fcntl(s->sock_fd, F_SETFL, new_delay_flag) == -1) - goto error; + goto done; #endif #else /* MS_WINDOWS */ arg = !block; if (ioctlsocket(s->sock_fd, FIONBIO, &arg) != 0) - goto error; + goto done; #endif /* MS_WINDOWS */ + + result = 0; + + done: Py_END_ALLOW_THREADS - return 0; - error: + if (result) { #ifndef MS_WINDOWS - PyErr_SetFromErrno(PyExc_OSError); + PyErr_SetFromErrno(PyExc_OSError); #else - PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); -#endif - return -1; + PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); +#endif + } + + return result; } static int -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 02:14:26 2016 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 19 Oct 2016 06:14:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161019061426.17963.62246.C99F8D92@psf.io> https://hg.python.org/cpython/rev/651922ea92b0 changeset: 104546:651922ea92b0 parent: 104544:554fb699af8c parent: 104545:ce0c96fd6b4c user: Benjamin Peterson date: Tue Oct 18 23:14:16 2016 -0700 summary: merge 3.6 files: Doc/library/email.parser.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 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 @@ -92,7 +92,7 @@ .. versionadded:: 3.2 .. versionchanged:: 3.3 Added the *policy* keyword. - .. versionchanged:: 3.6 _factory defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_factory* defaults to the policy ``message_factory``. .. method:: feed(data) @@ -148,7 +148,7 @@ .. versionchanged:: 3.3 Removed the *strict* argument that was deprecated in 2.4. Added the *policy* keyword. - .. versionchanged:: 3.6 _class defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_class* defaults to the policy ``message_factory``. .. method:: parse(fp, headersonly=False) @@ -197,7 +197,7 @@ .. versionchanged:: 3.3 Removed the *strict* argument. Added the *policy* keyword. - .. versionchanged:: 3.6 _class defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_class* defaults to the policy ``message_factory``. .. method:: parse(fp, headersonly=False) @@ -277,7 +277,7 @@ .. versionchanged:: 3.3 Removed the *strict* argument. Added the *policy* keyword. - .. versionchanged:: 3.6 _class defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_class* defaults to the policy ``message_factory``. Here's an example of how you might use :func:`message_from_bytes` at an -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 02:14:26 2016 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 19 Oct 2016 06:14:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_bold_arguments?= Message-ID: <20161019061426.12283.77892.DFAD41D0@psf.io> https://hg.python.org/cpython/rev/ce0c96fd6b4c changeset: 104545:ce0c96fd6b4c branch: 3.6 parent: 104543:4b5b233d4c98 user: Benjamin Peterson date: Tue Oct 18 23:14:08 2016 -0700 summary: bold arguments files: Doc/library/email.parser.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 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 @@ -92,7 +92,7 @@ .. versionadded:: 3.2 .. versionchanged:: 3.3 Added the *policy* keyword. - .. versionchanged:: 3.6 _factory defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_factory* defaults to the policy ``message_factory``. .. method:: feed(data) @@ -148,7 +148,7 @@ .. versionchanged:: 3.3 Removed the *strict* argument that was deprecated in 2.4. Added the *policy* keyword. - .. versionchanged:: 3.6 _class defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_class* defaults to the policy ``message_factory``. .. method:: parse(fp, headersonly=False) @@ -197,7 +197,7 @@ .. versionchanged:: 3.3 Removed the *strict* argument. Added the *policy* keyword. - .. versionchanged:: 3.6 _class defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_class* defaults to the policy ``message_factory``. .. method:: parse(fp, headersonly=False) @@ -277,7 +277,7 @@ .. versionchanged:: 3.3 Removed the *strict* argument. Added the *policy* keyword. - .. versionchanged:: 3.6 _class defaults to the policy ``message_factory``. + .. versionchanged:: 3.6 *_class* defaults to the policy ``message_factory``. Here's an example of how you might use :func:`message_from_bytes` at an -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 02:33:30 2016 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 19 Oct 2016 06:33:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_always_use_dou?= =?utf-8?q?ble_quotes_for_SystemTap_string_literals_=28closes_=2328472=29?= Message-ID: <20161019063329.110871.95841.823A40A7@psf.io> https://hg.python.org/cpython/rev/5c21df505684 changeset: 104547:5c21df505684 branch: 3.6 parent: 104545:ce0c96fd6b4c user: Benjamin Peterson date: Tue Oct 18 23:33:03 2016 -0700 summary: always use double quotes for SystemTap string literals (closes #28472) Patch by Roman Podoliaka. files: Doc/howto/instrumentation.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -210,7 +210,7 @@ .. code-block:: c - probe process('python').mark("function__entry") { + probe process("python").mark("function__entry") { filename = user_string($arg1); funcname = user_string($arg2); lineno = $arg3; @@ -219,7 +219,7 @@ thread_indent(1), funcname, filename, lineno); } - probe process('python').mark("function__return") { + probe process("python").mark("function__return") { filename = user_string($arg1); funcname = user_string($arg2); lineno = $arg3; @@ -234,7 +234,7 @@ $ stap \ show-call-hierarchy.stp \ - -c ./python test.py + -c "./python test.py" The output looks like this:: @@ -259,11 +259,11 @@ libpython shared library, and the probe's dotted path needs to reflect this. For example, this line from the above example:: - probe process('python').mark("function__entry") { + probe process("python").mark("function__entry") { should instead read:: - probe process('python').library("libpython3.6dm.so.1.0").mark("function__entry") { + probe process("python").library("libpython3.6dm.so.1.0").mark("function__entry") { (assuming a debug build of CPython 3.6) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 02:33:30 2016 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 19 Oct 2016 06:33:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42ICgjMjg0NzIp?= Message-ID: <20161019063330.32842.70237.500B52D4@psf.io> https://hg.python.org/cpython/rev/dc10bd89473b changeset: 104548:dc10bd89473b parent: 104546:651922ea92b0 parent: 104547:5c21df505684 user: Benjamin Peterson date: Tue Oct 18 23:33:24 2016 -0700 summary: merge 3.6 (#28472) files: Doc/howto/instrumentation.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -210,7 +210,7 @@ .. code-block:: c - probe process('python').mark("function__entry") { + probe process("python").mark("function__entry") { filename = user_string($arg1); funcname = user_string($arg2); lineno = $arg3; @@ -219,7 +219,7 @@ thread_indent(1), funcname, filename, lineno); } - probe process('python').mark("function__return") { + probe process("python").mark("function__return") { filename = user_string($arg1); funcname = user_string($arg2); lineno = $arg3; @@ -234,7 +234,7 @@ $ stap \ show-call-hierarchy.stp \ - -c ./python test.py + -c "./python test.py" The output looks like this:: @@ -259,11 +259,11 @@ libpython shared library, and the probe's dotted path needs to reflect this. For example, this line from the above example:: - probe process('python').mark("function__entry") { + probe process("python").mark("function__entry") { should instead read:: - probe process('python').library("libpython3.6dm.so.1.0").mark("function__entry") { + probe process("python").library("libpython3.6dm.so.1.0").mark("function__entry") { (assuming a debug build of CPython 3.6) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 04:13:06 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 19 Oct 2016 08:13:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2328476=3A_Reuse_ma?= =?utf-8?q?th=2Efactorial=28=29_in_test=5Frandom?= Message-ID: <20161019081141.27387.59191.F9649383@psf.io> https://hg.python.org/cpython/rev/c6588a7443a4 changeset: 104549:c6588a7443a4 user: Victor Stinner date: Wed Oct 19 10:11:37 2016 +0200 summary: Close #28476: Reuse math.factorial() in test_random Patch written by Francisco Couzo. files: Lib/test/test_random.py | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -5,7 +5,7 @@ import pickle import warnings from functools import partial -from math import log, exp, pi, fsum, sin +from math import log, exp, pi, fsum, sin, factorial from test import support from fractions import Fraction @@ -117,10 +117,6 @@ n = 5 pop = range(n) trials = 10000 # large num prevents false negatives without slowing normal case - def factorial(n): - if n == 0: - return 1 - return n * factorial(n - 1) for k in range(n): expected = factorial(n) // factorial(n-k) perms = {} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 05:08:59 2016 From: python-checkins at python.org (xavier.degaye) Date: Wed, 19 Oct 2016 09:08:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI2OTQ0?= =?utf-8?q?=3A_Fix_test=5Fposix_for_Android_where_=27id_-G=27_is_entirely_?= =?utf-8?q?wrong?= Message-ID: <20161019090858.38655.85864.BE5B1F3E@psf.io> https://hg.python.org/cpython/rev/fb3e65aff225 changeset: 104550:fb3e65aff225 branch: 3.6 parent: 104547:5c21df505684 user: Xavier de Gaye date: Wed Oct 19 11:00:26 2016 +0200 summary: Issue #26944: Fix test_posix for Android where 'id -G' is entirely wrong or missing the effective gid. files: Lib/test/test_posix.py | 17 ++++++++++------- Misc/NEWS | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -799,7 +799,11 @@ groups = idg.read().strip() ret = idg.close() - if ret is not None or not groups: + try: + idg_groups = set(int(g) for g in groups.split()) + except ValueError: + idg_groups = set() + if ret is not None or not idg_groups: raise unittest.SkipTest("need working 'id -G'") # Issues 16698: OS X ABIs prior to 10.6 have limits on getgroups() @@ -810,12 +814,11 @@ raise unittest.SkipTest("getgroups(2) is broken prior to 10.6") # 'id -G' and 'os.getgroups()' should return the same - # groups, ignoring order and duplicates. - # #10822 - it is implementation defined whether posix.getgroups() - # includes the effective gid so we include it anyway, since id -G does - self.assertEqual( - set([int(x) for x in groups.split()]), - set(posix.getgroups() + [posix.getegid()])) + # groups, ignoring order, duplicates, and the effective gid. + # #10822/#26944 - It is implementation defined whether + # posix.getgroups() includes the effective gid. + symdiff = idg_groups.symmetric_difference(posix.getgroups()) + self.assertTrue(not symdiff or symdiff == {posix.getegid()}) # tests for the posix *at functions follow diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Tests ----- +- Issue #26944: Fix test_posix for Android where 'id -G' is entirely wrong or + missing the effective gid. + - Issue #28409: regrtest: fix the parser of command line arguments. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 05:09:04 2016 From: python-checkins at python.org (xavier.degaye) Date: Wed, 19 Oct 2016 09:09:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326944=3A_Merge_with_3=2E6=2E?= Message-ID: <20161019090858.27413.90132.7B924AEF@psf.io> https://hg.python.org/cpython/rev/465c09937e85 changeset: 104551:465c09937e85 parent: 104549:c6588a7443a4 parent: 104550:fb3e65aff225 user: Xavier de Gaye date: Wed Oct 19 11:08:07 2016 +0200 summary: Issue #26944: Merge with 3.6. files: Lib/test/test_posix.py | 17 ++++++++++------- Misc/NEWS | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -799,7 +799,11 @@ groups = idg.read().strip() ret = idg.close() - if ret is not None or not groups: + try: + idg_groups = set(int(g) for g in groups.split()) + except ValueError: + idg_groups = set() + if ret is not None or not idg_groups: raise unittest.SkipTest("need working 'id -G'") # Issues 16698: OS X ABIs prior to 10.6 have limits on getgroups() @@ -810,12 +814,11 @@ raise unittest.SkipTest("getgroups(2) is broken prior to 10.6") # 'id -G' and 'os.getgroups()' should return the same - # groups, ignoring order and duplicates. - # #10822 - it is implementation defined whether posix.getgroups() - # includes the effective gid so we include it anyway, since id -G does - self.assertEqual( - set([int(x) for x in groups.split()]), - set(posix.getgroups() + [posix.getegid()])) + # groups, ignoring order, duplicates, and the effective gid. + # #10822/#26944 - It is implementation defined whether + # posix.getgroups() includes the effective gid. + symdiff = idg_groups.symmetric_difference(posix.getgroups()) + self.assertTrue(not symdiff or symdiff == {posix.getegid()}) # tests for the posix *at functions follow diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -326,6 +326,9 @@ Tests ----- +- Issue #26944: Fix test_posix for Android where 'id -G' is entirely wrong or + missing the effective gid. + - Issue #28409: regrtest: fix the parser of command line arguments. - Issue #28217: Adds _testconsole module to test console input. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:09 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Mark_up_None_as_literal_text=2E?= Message-ID: <20161019134608.33099.54417.2608A1CD@psf.io> https://hg.python.org/cpython/rev/a8d5b433bb36 changeset: 104553:a8d5b433bb36 branch: 3.5 parent: 104532:87aced4a9cf5 user: Serhiy Storchaka date: Wed Oct 19 16:29:26 2016 +0300 summary: Issue #19795: Mark up None as literal text. files: Doc/c-api/none.rst | 6 +++--- Doc/c-api/unicode.rst | 8 ++++---- Doc/howto/descriptor.rst | 2 +- Doc/howto/logging.rst | 2 +- Doc/howto/sorting.rst | 2 +- Doc/library/argparse.rst | 10 +++++----- Doc/library/asyncio-protocol.rst | 4 ++-- Doc/library/asyncore.rst | 2 +- Doc/library/bdb.rst | 2 +- Doc/library/collections.rst | 4 ++-- Doc/library/dis.rst | 10 +++++----- Doc/library/doctest.rst | 4 ++-- Doc/library/ensurepip.rst | 2 +- Doc/library/functools.rst | 2 +- Doc/library/http.server.rst | 2 +- Doc/library/imaplib.rst | 2 +- Doc/library/importlib.rst | 12 ++++++------ Doc/library/json.rst | 5 +++-- Doc/library/linecache.rst | 2 +- Doc/library/logging.config.rst | 2 +- Doc/library/logging.handlers.rst | 6 +++--- Doc/library/logging.rst | 8 ++++---- Doc/library/mmap.rst | 4 ++-- Doc/library/multiprocessing.rst | 10 +++++----- Doc/library/nntplib.rst | 2 +- Doc/library/optparse.rst | 4 ++-- Doc/library/os.rst | 4 ++-- Doc/library/queue.rst | 4 ++-- Doc/library/select.rst | 2 +- Doc/library/smtplib.rst | 11 ++++++----- Doc/library/sqlite3.rst | 8 ++++---- Doc/library/ssl.rst | 4 ++-- Doc/library/stdtypes.rst | 8 ++++---- Doc/library/string.rst | 2 +- Doc/library/subprocess.rst | 6 +++--- Doc/library/sys.rst | 2 +- Doc/library/test.rst | 4 ++-- Doc/library/threading.rst | 6 +++--- Doc/library/tkinter.ttk.rst | 2 +- Doc/library/turtle.rst | 10 +++++----- Doc/library/typing.rst | 2 +- Doc/library/unittest.mock.rst | 2 +- Doc/library/unittest.rst | 4 ++-- Doc/library/urllib.request.rst | 2 +- Doc/library/xml.sax.reader.rst | 2 +- Doc/library/zipapp.rst | 2 +- Doc/reference/datamodel.rst | 2 +- Doc/whatsnew/3.2.rst | 4 ++-- Doc/whatsnew/3.3.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- 50 files changed, 109 insertions(+), 107 deletions(-) diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -2,8 +2,8 @@ .. _noneobject: -The None Object ---------------- +The ``None`` Object +------------------- .. index:: object: None @@ -23,4 +23,4 @@ .. c:macro:: Py_RETURN_NONE Properly handle returning :c:data:`Py_None` from within a C function (that is, - increment the reference count of None and return it.) + increment the reference count of ``None`` and return it.) 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 @@ -1410,11 +1410,11 @@ decode characters. Decoding mappings must map single string characters to single Unicode -characters, integers (which are then interpreted as Unicode ordinals) or None +characters, integers (which are then interpreted as Unicode ordinals) or ``None`` (meaning "undefined mapping" and causing an error). Encoding mappings must map single Unicode characters to single string -characters, integers (which are then interpreted as Latin-1 ordinals) or None +characters, integers (which are then interpreted as Latin-1 ordinals) or ``None`` (meaning "undefined mapping" and causing an error). The mapping objects provided must only support the __getitem__ mapping @@ -1455,7 +1455,7 @@ *NULL* when an exception was raised by the codec. The *mapping* table must map Unicode ordinal integers to Unicode ordinal - integers or None (causing deletion of the character). + integers or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a @@ -1572,7 +1572,7 @@ resulting Unicode object. The mapping table must map Unicode ordinal integers to Unicode ordinal integers - or None (causing deletion of the character). + or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -302,7 +302,7 @@ While they could have been implemented that way, the actual C implementation of :c:type:`PyMethod_Type` in :source:`Objects/classobject.c` is a single object with two different representations depending on whether the :attr:`im_self` -field is set or is *NULL* (the C equivalent of *None*). +field is set or is *NULL* (the C equivalent of ``None``). Likewise, the effects of calling a method object depend on the :attr:`im_self` field. If set (meaning bound), the original function (stored in the diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -764,7 +764,7 @@ The handler's level is set to ``WARNING``, so all events at this and greater severities will be output. -To obtain the pre-3.2 behaviour, ``logging.lastResort`` can be set to *None*. +To obtain the pre-3.2 behaviour, ``logging.lastResort`` can be set to ``None``. .. _library-config: diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -24,7 +24,7 @@ [1, 2, 3, 4, 5] You can also use the :meth:`list.sort` method. It modifies the list -in-place (and returns *None* to avoid confusion). Usually it's less convenient +in-place (and returns ``None`` to avoid confusion). Usually it's less convenient than :func:`sorted` - but if you don't need the original list, it's slightly more efficient. diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1552,7 +1552,7 @@ positional arguments * description - description for the sub-parser group in help output, by - default None + default ``None`` * prog - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the @@ -1565,12 +1565,12 @@ encountered at the command line * dest_ - name of the attribute under which sub-command name will be - stored; by default None and no value is stored - - * help_ - help for sub-parser group in help output, by default None + stored; by default ``None`` and no value is stored + + * help_ - help for sub-parser group in help output, by default ``None`` * metavar_ - string presenting available sub-commands in help; by default it - is None and presents sub-commands in form {cmd1, cmd2, ..} + is ``None`` and presents sub-commands in form {cmd1, cmd2, ..} Some example usage:: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -372,10 +372,10 @@ (for example by calling :meth:`write_eof`, if the other end also uses asyncio). - This method may return a false value (including None), in which case + This method may return a false value (including ``None``), in which case the transport will close itself. Conversely, if this method returns a true value, closing the transport is up to the protocol. Since the - default implementation returns None, it implicitly closes the connection. + default implementation returns ``None``, it implicitly closes the connection. .. note:: Some transports such as SSL don't support half-closed connections, diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -57,7 +57,7 @@ Enter a polling loop that terminates after count passes or all open channels have been closed. All arguments are optional. The *count* - parameter defaults to None, resulting in the loop terminating only when all + parameter defaults to ``None``, resulting in the loop terminating only when all channels have been closed. The *timeout* argument sets the timeout parameter for the appropriate :func:`~select.select` or :func:`~select.poll` call, measured in seconds; the default is 30 seconds. The *use_poll* diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -241,7 +241,7 @@ .. method:: set_continue() Stop only at breakpoints or when finished. If there are no breakpoints, - set the system trace function to None. + set the system trace function to ``None``. .. method:: set_quit() diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -412,7 +412,7 @@ position of the underlying data representation. - If *maxlen* is not specified or is *None*, deques may grow to an + If *maxlen* is not specified or is ``None``, deques may grow to an arbitrary length. Otherwise, the deque is bounded to the specified maximum length. Once a bounded length deque is full, when new items are added, a corresponding number of items are discarded from the opposite end. Bounded @@ -520,7 +520,7 @@ .. attribute:: maxlen - Maximum size of a deque or *None* if unbounded. + Maximum size of a deque or ``None`` if unbounded. .. versionadded:: 3.1 diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -56,12 +56,12 @@ notably :func:`get_instructions`, as iterating over a :class:`Bytecode` instance yields the bytecode operations as :class:`Instruction` instances. - If *first_line* is not None, it indicates the line number that should be + If *first_line* is not ``None``, it indicates the line number that should be reported for the first source line in the disassembled code. Otherwise, the source line information (if any) is taken directly from the disassembled code object. - If *current_offset* is not None, it refers to an instruction offset in the + If *current_offset* is not ``None``, it refers to an instruction offset in the disassembled code. Setting this means :meth:`.dis` will display a "current instruction" marker against the specified opcode. @@ -197,7 +197,7 @@ The iterator generates a series of :class:`Instruction` named tuples giving the details of each operation in the supplied code. - If *first_line* is not None, it indicates the line number that should be + If *first_line* is not ``None``, it indicates the line number that should be reported for the first source line in the disassembled code. Otherwise, the source line information (if any) is taken directly from the disassembled code object. @@ -249,7 +249,7 @@ .. data:: arg - numeric argument to operation (if any), otherwise None + numeric argument to operation (if any), otherwise ``None`` .. data:: argval @@ -269,7 +269,7 @@ .. data:: starts_line - line started by this opcode (if any), otherwise None + line started by this opcode (if any), otherwise ``None`` .. data:: is_jump_target diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1215,7 +1215,7 @@ .. attribute:: docstring - The string that the test was extracted from, or 'None' if the string is + The string that the test was extracted from, or ``None`` if the string is unavailable, or if the test was not extracted from a string. @@ -1320,7 +1320,7 @@ not specified, then ``obj.__name__`` is used. The optional parameter *module* is the module that contains the given object. - If the module is not specified or is None, then the test finder will attempt + If the module is not specified or is ``None``, then the test finder will attempt to automatically determine the correct module. The object's module is used: * As a default namespace, if *globs* is not specified. diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -96,7 +96,7 @@ Bootstraps ``pip`` into the current or designated environment. *root* specifies an alternative root directory to install relative to. - If *root* is None, then installation uses the default install location + If *root* is ``None``, then installation uses the default install location for the current environment. *upgrade* indicates whether or not to upgrade an existing installation diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -52,7 +52,7 @@ Since a dictionary is used to cache results, the positional and keyword arguments to the function must be hashable. - If *maxsize* is set to None, the LRU feature is disabled and the cache can + If *maxsize* is set to ``None``, the LRU feature is disabled and the cache can grow without bound. The LRU feature performs best when *maxsize* is a power-of-two. diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -277,7 +277,7 @@ .. method:: date_time_string(timestamp=None) - Returns the date and time given by *timestamp* (which must be None or in + Returns the date and time given by *timestamp* (which must be ``None`` or in the format returned by :func:`time.time`), formatted for a message header. If *timestamp* is omitted, it uses the current date and time. diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -120,7 +120,7 @@ Parse an IMAP4 ``INTERNALDATE`` string and return corresponding local time. The return value is a :class:`time.struct_time` tuple or - None if the string has wrong format. + ``None`` if the string has wrong format. .. function:: Int2AP(num) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1044,7 +1044,7 @@ (``__loader__``) The loader to use for loading. For namespace packages this should be - set to None. + set to ``None``. .. attribute:: origin @@ -1052,33 +1052,33 @@ Name of the place from which the module is loaded, e.g. "builtin" for built-in modules and the filename for modules loaded from source. - Normally "origin" should be set, but it may be None (the default) + Normally "origin" should be set, but it may be ``None`` (the default) which indicates it is unspecified. .. attribute:: submodule_search_locations (``__path__``) - List of strings for where to find submodules, if a package (None + List of strings for where to find submodules, if a package (``None`` otherwise). .. attribute:: loader_state Container of extra module-specific data for use during loading (or - None). + ``None``). .. attribute:: cached (``__cached__``) - String for where the compiled module should be stored (or None). + String for where the compiled module should be stored (or ``None``). .. attribute:: parent (``__package__``) (Read-only) Fully-qualified name of the package to which the module - belongs as a submodule (or None). + belongs as a submodule (or ``None``). .. attribute:: has_location diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -397,8 +397,9 @@ (to raise :exc:`TypeError`). If *skipkeys* is false (the default), then it is a :exc:`TypeError` to - attempt encoding of keys that are not str, int, float or None. If - *skipkeys* is true, such items are simply skipped. + attempt encoding of keys that are not :class:`str`, :class:`int`, + :class:`float` or ``None``. If *skipkeys* is true, such items are simply + skipped. If *ensure_ascii* is true (the default), the output is guaranteed to have all incoming non-ASCII characters escaped. If *ensure_ascii* is diff --git a/Doc/library/linecache.rst b/Doc/library/linecache.rst --- a/Doc/library/linecache.rst +++ b/Doc/library/linecache.rst @@ -51,7 +51,7 @@ .. function:: lazycache(filename, module_globals) Capture enough detail about a non-file-based module to permit getting its - lines later via :func:`getline` even if *module_globals* is None in the later + lines later via :func:`getline` even if *module_globals* is ``None`` in the later call. This avoids doing I/O until a line is actually needed, without having to carry the module globals around indefinitely. 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 @@ -138,7 +138,7 @@ across the socket, such that the ``verify`` callable can perform signature verification and/or decryption. The ``verify`` callable is called with a single argument - the bytes received across the socket - and should - return the bytes to be processed, or None to indicate that the bytes should + return the bytes to be processed, or ``None`` to indicate that the bytes should be discarded. The returned bytes could be the same as the passed in bytes (e.g. when only verification is done), or they could be completely different (perhaps if decryption were performed). diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -80,7 +80,7 @@ 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 + :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. @@ -156,7 +156,7 @@ 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 + :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. @@ -261,7 +261,7 @@ 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 + ``'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. diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -296,7 +296,7 @@ Finds the caller's source filename and line number. Returns the filename, line number, function name and stack information as a 4-element tuple. The stack - information is returned as *None* unless *stack_info* is *True*. + information is returned as ``None`` unless *stack_info* is *True*. .. method:: Logger.handle(record) @@ -672,7 +672,7 @@ :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. + or ``None`` if no exception information is available. :param func: The name of the function or method from which the logging call was invoked. :param sinfo: A text string representing stack information from the base of @@ -754,7 +754,7 @@ | | | (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*. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ @@ -1187,7 +1187,7 @@ :lno: The line number in the file where the logging call was made. :msg: The logging message. :args: The arguments for the logging message. - :exc_info: An exception tuple, or None. + :exc_info: An exception tuple, or ``None``. :func: The name of the function or method which invoked the logging call. :sinfo: A stack traceback such as is provided by diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -204,13 +204,13 @@ .. method:: read([n]) Return a :class:`bytes` containing up to *n* bytes starting from the - current file position. If the argument is omitted, *None* or negative, + current file position. If the argument is omitted, ``None`` or negative, return all bytes from the current file position to the end of the mapping. The file position is updated to point after the bytes that were returned. .. versionchanged:: 3.3 - Argument can be omitted or *None*. + Argument can be omitted or ``None``. .. method:: read_byte() diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -942,7 +942,7 @@ Return a context object which has the same attributes as the :mod:`multiprocessing` module. - If *method* is *None* then the default context is returned. + If *method* is ``None`` then the default context is returned. Otherwise *method* should be ``'fork'``, ``'spawn'``, ``'forkserver'``. :exc:`ValueError` is raised if the specified start method is not available. @@ -956,10 +956,10 @@ If the start method has not been fixed and *allow_none* is false, then the start method is fixed to the default and the name is returned. If the start method has not been fixed and *allow_none* - is true then *None* is returned. + is true then ``None`` is returned. The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'`` - or *None*. ``'fork'`` is the default on Unix, while ``'spawn'`` is + or ``None``. ``'fork'`` is the default on Unix, while ``'spawn'`` is the default on Windows. .. versionadded:: 3.4 @@ -2028,7 +2028,7 @@ *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable - unused resources to be freed. The default *maxtasksperchild* is None, which + unused resources to be freed. The default *maxtasksperchild* is ``None``, which means worker processes will live as long as the pool. *context* can be used to specify the context used for starting @@ -2298,7 +2298,7 @@ ``None`` then digest authentication is used. If *authkey* is a byte string then it will be used as the - authentication key; otherwise it must be *None*. + authentication key; otherwise it must be ``None``. If *authkey* is ``None`` and *authenticate* is ``True`` then ``current_process().authkey`` is used as the authentication key. If diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -220,7 +220,7 @@ .. method:: NNTP.login(user=None, password=None, usenetrc=True) Send ``AUTHINFO`` commands with the user name and password. If *user* - and *password* are None and *usenetrc* is true, credentials from + and *password* are ``None`` and *usenetrc* is true, credentials from ``~/.netrc`` will be used if possible. Unless intentionally delayed, login is normally performed during the diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -2026,12 +2026,12 @@ values.ensure_value(attr, value) - If the ``attr`` attribute of ``values`` doesn't exist or is None, then + If the ``attr`` attribute of ``values`` doesn't exist or is ``None``, then ensure_value() first sets it to ``value``, and then returns 'value. This is very handy for actions like ``"extend"``, ``"append"``, and ``"count"``, all of which accumulate data in a variable and expect that variable to be of a certain type (a list for the first two, an integer for the latter). Using :meth:`ensure_value` means that scripts using your action don't have to worry about setting a default value for the option destinations in question; they - can just leave the default as None and :meth:`ensure_value` will take care of + can just leave the default as ``None`` and :meth:`ensure_value` will take care of getting it right when it's needed. diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -220,7 +220,7 @@ executable, similar to a shell, when launching a process. *env*, when specified, should be an environment variable dictionary to lookup the PATH in. - By default, when *env* is None, :data:`environ` is used. + By default, when *env* is ``None``, :data:`environ` is used. .. versionadded:: 3.2 @@ -3621,7 +3621,7 @@ .. function:: cpu_count() - Return the number of CPUs in the system. Returns None if undetermined. + Return the number of CPUs in the system. Returns ``None`` if undetermined. .. versionadded:: 3.4 diff --git a/Doc/library/queue.rst b/Doc/library/queue.rst --- a/Doc/library/queue.rst +++ b/Doc/library/queue.rst @@ -103,7 +103,7 @@ .. method:: Queue.put(item, block=True, timeout=None) Put *item* into the queue. If optional args *block* is true and *timeout* is - None (the default), block if necessary until a free slot is available. If + ``None`` (the default), block if necessary until a free slot is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Full` exception if no free slot was available within that time. Otherwise (*block* is false), put an item on the queue if a free slot is @@ -119,7 +119,7 @@ .. method:: Queue.get(block=True, timeout=None) Remove and return an item from the queue. If optional args *block* is true and - *timeout* is None (the default), block if necessary until an item is available. + *timeout* is ``None`` (the default), block if necessary until an item is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Empty` exception if no item was available within that time. Otherwise (*block* is false), return an item if one is immediately available, diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -459,7 +459,7 @@ Low level interface to kevent - - changelist must be an iterable of kevent object or None + - changelist must be an iterable of kevent object or ``None`` - max_events must be 0 or a positive integer - timeout in seconds (floats possible) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -341,10 +341,10 @@ :rfc:`4954` "initial response" bytes which will be encoded and sent with the ``AUTH`` command as below. If the ``authobject()`` does not support an initial response (e.g. because it requires a challenge), it should return - None when called with ``challenge=None``. If *initial_response_ok* is - false, then ``authobject()`` will not be called first with None. + ``None`` when called with ``challenge=None``. If *initial_response_ok* is + false, then ``authobject()`` will not be called first with ``None``. - If the initial response check returns None, or if *initial_response_ok* is + If the initial response check returns ``None``, or if *initial_response_ok* is false, ``authobject()`` will be called to process the server's challenge response; the *challenge* argument it is passed will be a ``bytes``. It should return ``bytes`` *data* that will be base64 encoded and sent to the @@ -374,8 +374,9 @@ If *keyfile* and *certfile* are provided, these are passed to the :mod:`socket` module's :func:`ssl` function. - Optional *context* parameter is a :class:`ssl.SSLContext` object; This is an alternative to - using a keyfile and a certfile and if specified both *keyfile* and *certfile* should be None. + Optional *context* parameter is a :class:`ssl.SSLContext` object; This is + an alternative to using a keyfile and a certfile and if specified both + *keyfile* and *certfile* should be ``None``. If there has been no previous ``EHLO`` or ``HELO`` command this session, this method tries ESMTP ``EHLO`` first. diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -339,7 +339,7 @@ called as the SQL function. The function can return any of the types supported by SQLite: bytes, str, int, - float and None. + float and ``None``. Example: @@ -356,7 +356,7 @@ final result of the aggregate. The ``finalize`` method can return any of the types supported by SQLite: - bytes, str, int, float and None. + bytes, str, int, float and ``None``. Example: @@ -378,7 +378,7 @@ .. literalinclude:: ../includes/sqlite3/collation_reverse.py - To remove a collation, call ``create_collation`` with None as callable:: + To remove a collation, call ``create_collation`` with ``None`` as callable:: con.create_collation("reverse", None) @@ -934,7 +934,7 @@ (or none at all) via the *isolation_level* parameter to the :func:`connect` call, or via the :attr:`isolation_level` property of connections. -If you want **autocommit mode**, then set :attr:`isolation_level` to None. +If you want **autocommit mode**, then set :attr:`isolation_level` to ``None``. Otherwise leave it at its default, which will result in a plain "BEGIN" statement, or set it to one of SQLite's supported isolation levels: "DEFERRED", diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -455,8 +455,8 @@ :meth:`SSLContext.set_default_verify_paths`. The return value is a :term:`named tuple` ``DefaultVerifyPaths``: - * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist, - * :attr:`capath` - resolved path to capath or None if the directory doesn't exist, + * :attr:`cafile` - resolved path to cafile or ``None`` if the file doesn't exist, + * :attr:`capath` - resolved path to capath or ``None`` if the directory doesn't exist, * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile, * :attr:`openssl_cafile` - hard coded path to a cafile, * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath, diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1751,13 +1751,13 @@ If there is only one argument, it must be a dictionary mapping Unicode ordinals (integers) or characters (strings of length 1) to Unicode ordinals, - strings (of arbitrary lengths) or None. Character keys will then be + strings (of arbitrary lengths) or ``None``. Character keys will then be converted to ordinals. If there are two arguments, they must be strings of equal length, and in the resulting dictionary, each character in x will be mapped to the character at the same position in y. If there is a third argument, it must be a string, - whose characters will be mapped to None in the result. + whose characters will be mapped to ``None`` in the result. .. method:: str.partition(sep) @@ -3751,7 +3751,7 @@ memory as an N-dimensional array. .. versionchanged:: 3.3 - An empty tuple instead of None when ndim = 0. + An empty tuple instead of ``None`` when ndim = 0. .. attribute:: strides @@ -3759,7 +3759,7 @@ access each element for each dimension of the array. .. versionchanged:: 3.3 - An empty tuple instead of None when ndim = 0. + An empty tuple instead of ``None`` when ndim = 0. .. attribute:: suboffsets diff --git a/Doc/library/string.rst b/Doc/library/string.rst --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -431,7 +431,7 @@ In addition to the above presentation types, integers can be formatted with the floating point presentation types listed below (except -``'n'`` and None). When doing so, :func:`float` is used to convert the +``'n'`` and ``None``). When doing so, :func:`float` is used to convert the integer to a floating point number before formatting. The available presentation types for floating point and decimal values are: diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -104,17 +104,17 @@ .. attribute:: stdout Captured stdout from the child process. A bytes sequence, or a string if - :func:`run` was called with ``universal_newlines=True``. None if stdout + :func:`run` was called with ``universal_newlines=True``. ``None`` if stdout was not captured. If you ran the process with ``stderr=subprocess.STDOUT``, stdout and stderr will be combined in this attribute, and :attr:`stderr` will be - None. + ``None``. .. attribute:: stderr Captured stderr from the child process. A bytes sequence, or a string if - :func:`run` was called with ``universal_newlines=True``. None if stderr + :func:`run` was called with ``universal_newlines=True``. ``None`` if stderr was not captured. .. method:: check_returncode() diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1192,7 +1192,7 @@ .. note:: Under some conditions ``stdin``, ``stdout`` and ``stderr`` as well as the original values ``__stdin__``, ``__stdout__`` and ``__stderr__`` can be - None. It is usually the case for Windows GUI apps that aren't connected + ``None``. It is usually the case for Windows GUI apps that aren't connected to a console and Python apps started with :program:`pythonw`. diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -398,7 +398,7 @@ A context manager that creates a temporary directory at *path* and yields the directory. - If *path* is None, the temporary directory is created using + If *path* is ``None``, the temporary directory is created using :func:`tempfile.mkdtemp`. If *quiet* is ``False``, the context manager raises an exception on error. Otherwise, if *path* is specified and cannot be created, only a warning is issued. @@ -421,7 +421,7 @@ The context manager creates a temporary directory in the current directory with name *name* before temporarily changing the current - working directory. If *name* is None, the temporary directory is + working directory. If *name* is ``None``, the temporary directory is created using :func:`tempfile.mkdtemp`. If *quiet* is ``False`` and it is not possible to create or change diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -714,7 +714,7 @@ without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true. - When invoked with a *timeout* other than None, it will block for at + When invoked with a *timeout* other than ``None``, it will block for at most *timeout* seconds. If acquire does not complete successfully in that interval, return false. Return true otherwise. @@ -854,8 +854,8 @@ Create a timer that will run *function* with arguments *args* and keyword arguments *kwargs*, after *interval* seconds have passed. - If *args* is None (the default) then an empty list will be used. - If *kwargs* is None (the default) then an empty dict will be used. + If *args* is ``None`` (the default) then an empty list will be used. + If *kwargs* is ``None`` (the default) then an empty dict will be used. .. versionchanged:: 3.3 changed from a factory function to a class. diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -1404,7 +1404,7 @@ Layouts ^^^^^^^ -A layout can be just None, if it takes no options, or a dict of +A layout can be just ``None``, if it takes no options, or a dict of options specifying how to arrange the element. The layout mechanism uses a simplified version of the pack geometry manager: given an initial cavity, each element is allocated a parcel. Valid diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -549,7 +549,7 @@ :param n: an integer (or ``None``) - Delete all or first/last *n* of turtle's stamps. If *n* is None, delete + Delete all or first/last *n* of turtle's stamps. If *n* is ``None``, delete all stamps, if *n* > 0 delete first *n* stamps, else if *n* < 0 delete last *n* stamps. @@ -1799,7 +1799,7 @@ Pop up a dialog window for input of a string. Parameter title is the title of the dialog window, propmt is a text mostly describing what information to input. - Return the string input. If the dialog is canceled, return None. :: + Return the string input. If the dialog is canceled, return ``None``. :: >>> screen.textinput("NIM", "Name of first player:") @@ -1819,7 +1819,7 @@ The number input must be in the range minval .. maxval if these are given. If not, a hint is issued and the dialog remains open for correction. - Return the number input. If the dialog is canceled, return None. :: + Return the number input. If the dialog is canceled, return ``None``. :: >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000) @@ -1984,10 +1984,10 @@ :param height: if an integer, the height in pixels, if a float, a fraction of the screen; default is 75% of screen :param startx: if positive, starting position in pixels from the left - edge of the screen, if negative from the right edge, if None, + edge of the screen, if negative from the right edge, if ``None``, center window horizontally :param starty: if positive, starting position in pixels from the top - edge of the screen, if negative from the bottom edge, if None, + edge of the screen, if negative from the bottom edge, if ``None``, center window vertically .. doctest:: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -706,7 +706,7 @@ This is often the same as ``obj.__annotations__``, but it handles forward references encoded as string literals, and if necessary - adds ``Optional[t]`` if a default value equal to None is set. + adds ``Optional[t]`` if a default value equal to ``None`` is set. .. decorator:: overload diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -244,7 +244,7 @@ .. versionadded:: 3.5 - * *wraps*: Item for the mock object to wrap. If *wraps* is not None then + * *wraps*: Item for the mock object to wrap. If *wraps* is not ``None`` then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -868,7 +868,7 @@ .. method:: assertIsNone(expr, msg=None) assertIsNotNone(expr, msg=None) - Test that *expr* is (or is not) None. + Test that *expr* is (or is not) ``None``. .. versionadded:: 3.1 @@ -1340,7 +1340,7 @@ methods that delegate to it), :meth:`assertDictEqual` and :meth:`assertMultiLineEqual`. - Setting ``maxDiff`` to None means that there is no maximum length of + Setting ``maxDiff`` to ``None`` means that there is no maximum length of diffs. .. versionadded:: 3.2 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 @@ -476,7 +476,7 @@ .. attribute:: Request.data - The entity body for the request, or None if not specified. + The entity body for the request, or ``None`` if not specified. .. versionchanged:: 3.4 Changing value of :attr:`Request.data` now deletes "Content-Length" diff --git a/Doc/library/xml.sax.reader.rst b/Doc/library/xml.sax.reader.rst --- a/Doc/library/xml.sax.reader.rst +++ b/Doc/library/xml.sax.reader.rst @@ -308,7 +308,7 @@ Get the byte stream for this input source. The getEncoding method will return the character encoding for this byte stream, - or None if unknown. + or ``None`` if unknown. .. method:: InputSource.setCharacterStream(charfile) diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -121,7 +121,7 @@ the archive will be written to that file. * If it is an open file object, the archive will be written to that file object, which must be open for writing in bytes mode. - * If the target is omitted (or None), the source must be a directory + * If the target is omitted (or ``None``), the source must be a directory and the target will be a file with the same name as the source, with a ``.pyz`` extension added. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -767,7 +767,7 @@ dictionary containing the class's namespace; :attr:`~class.__bases__` is a tuple (possibly empty or a singleton) containing the base classes, in the order of their occurrence in the base class list; :attr:`__doc__` is the - class's documentation string, or None if undefined. + class's documentation string, or ``None`` if undefined. Class instances .. index:: diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1439,7 +1439,7 @@ be a :term:`keyword argument`. The user-supplied filter function accepts a :class:`~tarfile.TarInfo` object and returns an updated :class:`~tarfile.TarInfo` object, or if it wants the file to be excluded, the -function can return *None*:: +function can return ``None``:: >>> import tarfile, glob @@ -1488,7 +1488,7 @@ syntax. The :func:`ast.literal_eval` function serves as a secure alternative to the builtin :func:`eval` function which is easily abused. Python 3.2 adds :class:`bytes` and :class:`set` literals to the list of supported types: -strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. +strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and ``None``. :: 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 @@ -182,7 +182,7 @@ * The maximum number of dimensions is officially limited to 64. * The representation of empty shape, strides and suboffsets is now - an empty tuple instead of None. + an empty tuple instead of ``None``. * Accessing a memoryview element with format 'B' (unsigned bytes) now returns an integer (in accordance with the struct module syntax). diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -161,7 +161,7 @@ * :ref:`Safe object finalization ` (:pep:`442`). * Leveraging :pep:`442`, in most cases :ref:`module globals are no longer set - to None during finalization ` (:issue:`18214`). + to ``None`` during finalization ` (:issue:`18214`). * :ref:`Configurable memory allocators ` (:pep:`445`). * :ref:`Argument Clinic ` (:pep:`436`). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:09 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2319795=3A_Mark_up_None_as_literal_text=2E?= Message-ID: <20161019134609.11740.13435.02EBD992@psf.io> https://hg.python.org/cpython/rev/2e97ed8e7e3c changeset: 104554:2e97ed8e7e3c branch: 3.6 parent: 104550:fb3e65aff225 parent: 104553:a8d5b433bb36 user: Serhiy Storchaka date: Wed Oct 19 16:37:13 2016 +0300 summary: Issue #19795: Mark up None as literal text. files: Doc/c-api/none.rst | 6 +++--- Doc/c-api/unicode.rst | 8 ++++---- Doc/howto/descriptor.rst | 2 +- Doc/howto/logging.rst | 2 +- Doc/howto/sorting.rst | 2 +- Doc/library/argparse.rst | 10 +++++----- Doc/library/asyncio-protocol.rst | 4 ++-- Doc/library/asyncore.rst | 2 +- Doc/library/bdb.rst | 2 +- Doc/library/code.rst | 2 +- Doc/library/collections.rst | 4 ++-- Doc/library/dis.rst | 10 +++++----- Doc/library/doctest.rst | 4 ++-- Doc/library/ensurepip.rst | 2 +- Doc/library/functools.rst | 2 +- Doc/library/http.server.rst | 2 +- Doc/library/imaplib.rst | 2 +- Doc/library/importlib.rst | 12 ++++++------ Doc/library/json.rst | 5 +++-- Doc/library/linecache.rst | 2 +- Doc/library/logging.config.rst | 2 +- Doc/library/logging.handlers.rst | 6 +++--- Doc/library/logging.rst | 8 ++++---- Doc/library/mmap.rst | 4 ++-- Doc/library/multiprocessing.rst | 10 +++++----- Doc/library/nntplib.rst | 2 +- Doc/library/optparse.rst | 4 ++-- Doc/library/os.rst | 4 ++-- Doc/library/queue.rst | 4 ++-- Doc/library/select.rst | 2 +- Doc/library/smtplib.rst | 11 ++++++----- Doc/library/socket.rst | 4 ++-- Doc/library/sqlite3.rst | 8 ++++---- Doc/library/ssl.rst | 4 ++-- Doc/library/stdtypes.rst | 8 ++++---- Doc/library/string.rst | 2 +- Doc/library/subprocess.rst | 6 +++--- Doc/library/sys.rst | 2 +- Doc/library/test.rst | 4 ++-- Doc/library/threading.rst | 6 +++--- Doc/library/timeit.rst | 2 +- Doc/library/tkinter.ttk.rst | 2 +- Doc/library/turtle.rst | 10 +++++----- Doc/library/typing.rst | 2 +- Doc/library/unittest.mock.rst | 2 +- Doc/library/unittest.rst | 4 ++-- Doc/library/urllib.request.rst | 2 +- Doc/library/xml.sax.reader.rst | 2 +- Doc/library/zipapp.rst | 2 +- Doc/reference/datamodel.rst | 2 +- Doc/whatsnew/3.2.rst | 4 ++-- Doc/whatsnew/3.3.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- 53 files changed, 113 insertions(+), 111 deletions(-) diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -2,8 +2,8 @@ .. _noneobject: -The None Object ---------------- +The ``None`` Object +------------------- .. index:: object: None @@ -23,4 +23,4 @@ .. c:macro:: Py_RETURN_NONE Properly handle returning :c:data:`Py_None` from within a C function (that is, - increment the reference count of None and return it.) + increment the reference count of ``None`` and return it.) 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 @@ -1415,11 +1415,11 @@ decode characters. Decoding mappings must map single string characters to single Unicode -characters, integers (which are then interpreted as Unicode ordinals) or None +characters, integers (which are then interpreted as Unicode ordinals) or ``None`` (meaning "undefined mapping" and causing an error). Encoding mappings must map single Unicode characters to single string -characters, integers (which are then interpreted as Latin-1 ordinals) or None +characters, integers (which are then interpreted as Latin-1 ordinals) or ``None`` (meaning "undefined mapping" and causing an error). The mapping objects provided must only support the __getitem__ mapping @@ -1460,7 +1460,7 @@ *NULL* when an exception was raised by the codec. The *mapping* table must map Unicode ordinal integers to Unicode ordinal - integers or None (causing deletion of the character). + integers or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a @@ -1577,7 +1577,7 @@ resulting Unicode object. The mapping table must map Unicode ordinal integers to Unicode ordinal integers - or None (causing deletion of the character). + or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -302,7 +302,7 @@ While they could have been implemented that way, the actual C implementation of :c:type:`PyMethod_Type` in :source:`Objects/classobject.c` is a single object with two different representations depending on whether the :attr:`im_self` -field is set or is *NULL* (the C equivalent of *None*). +field is set or is *NULL* (the C equivalent of ``None``). Likewise, the effects of calling a method object depend on the :attr:`im_self` field. If set (meaning bound), the original function (stored in the diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -764,7 +764,7 @@ The handler's level is set to ``WARNING``, so all events at this and greater severities will be output. -To obtain the pre-3.2 behaviour, ``logging.lastResort`` can be set to *None*. +To obtain the pre-3.2 behaviour, ``logging.lastResort`` can be set to ``None``. .. _library-config: diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -24,7 +24,7 @@ [1, 2, 3, 4, 5] You can also use the :meth:`list.sort` method. It modifies the list -in-place (and returns *None* to avoid confusion). Usually it's less convenient +in-place (and returns ``None`` to avoid confusion). Usually it's less convenient than :func:`sorted` - but if you don't need the original list, it's slightly more efficient. diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1552,7 +1552,7 @@ positional arguments * description - description for the sub-parser group in help output, by - default None + default ``None`` * prog - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the @@ -1565,12 +1565,12 @@ encountered at the command line * dest_ - name of the attribute under which sub-command name will be - stored; by default None and no value is stored - - * help_ - help for sub-parser group in help output, by default None + stored; by default ``None`` and no value is stored + + * help_ - help for sub-parser group in help output, by default ``None`` * metavar_ - string presenting available sub-commands in help; by default it - is None and presents sub-commands in form {cmd1, cmd2, ..} + is ``None`` and presents sub-commands in form {cmd1, cmd2, ..} Some example usage:: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -372,10 +372,10 @@ (for example by calling :meth:`write_eof`, if the other end also uses asyncio). - This method may return a false value (including None), in which case + This method may return a false value (including ``None``), in which case the transport will close itself. Conversely, if this method returns a true value, closing the transport is up to the protocol. Since the - default implementation returns None, it implicitly closes the connection. + default implementation returns ``None``, it implicitly closes the connection. .. note:: Some transports such as SSL don't support half-closed connections, diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -57,7 +57,7 @@ Enter a polling loop that terminates after count passes or all open channels have been closed. All arguments are optional. The *count* - parameter defaults to None, resulting in the loop terminating only when all + parameter defaults to ``None``, resulting in the loop terminating only when all channels have been closed. The *timeout* argument sets the timeout parameter for the appropriate :func:`~select.select` or :func:`~select.poll` call, measured in seconds; the default is 30 seconds. The *use_poll* diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -241,7 +241,7 @@ .. method:: set_continue() Stop only at breakpoints or when finished. If there are no breakpoints, - set the system trace function to None. + set the system trace function to ``None``. .. method:: set_quit() diff --git a/Doc/library/code.rst b/Doc/library/code.rst --- a/Doc/library/code.rst +++ b/Doc/library/code.rst @@ -150,7 +150,7 @@ The optional *exitmsg* argument specifies an exit message printed when exiting. Pass the empty string to suppress the exit message. If *exitmsg* is not given or - None, a default message is printed. + ``None``, a default message is printed. .. versionchanged:: 3.4 To suppress printing any banner, pass an empty string. diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -412,7 +412,7 @@ position of the underlying data representation. - If *maxlen* is not specified or is *None*, deques may grow to an + If *maxlen* is not specified or is ``None``, deques may grow to an arbitrary length. Otherwise, the deque is bounded to the specified maximum length. Once a bounded length deque is full, when new items are added, a corresponding number of items are discarded from the opposite end. Bounded @@ -520,7 +520,7 @@ .. attribute:: maxlen - Maximum size of a deque or *None* if unbounded. + Maximum size of a deque or ``None`` if unbounded. .. versionadded:: 3.1 diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -56,12 +56,12 @@ notably :func:`get_instructions`, as iterating over a :class:`Bytecode` instance yields the bytecode operations as :class:`Instruction` instances. - If *first_line* is not None, it indicates the line number that should be + If *first_line* is not ``None``, it indicates the line number that should be reported for the first source line in the disassembled code. Otherwise, the source line information (if any) is taken directly from the disassembled code object. - If *current_offset* is not None, it refers to an instruction offset in the + If *current_offset* is not ``None``, it refers to an instruction offset in the disassembled code. Setting this means :meth:`.dis` will display a "current instruction" marker against the specified opcode. @@ -197,7 +197,7 @@ The iterator generates a series of :class:`Instruction` named tuples giving the details of each operation in the supplied code. - If *first_line* is not None, it indicates the line number that should be + If *first_line* is not ``None``, it indicates the line number that should be reported for the first source line in the disassembled code. Otherwise, the source line information (if any) is taken directly from the disassembled code object. @@ -249,7 +249,7 @@ .. data:: arg - numeric argument to operation (if any), otherwise None + numeric argument to operation (if any), otherwise ``None`` .. data:: argval @@ -269,7 +269,7 @@ .. data:: starts_line - line started by this opcode (if any), otherwise None + line started by this opcode (if any), otherwise ``None`` .. data:: is_jump_target diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1215,7 +1215,7 @@ .. attribute:: docstring - The string that the test was extracted from, or 'None' if the string is + The string that the test was extracted from, or ``None`` if the string is unavailable, or if the test was not extracted from a string. @@ -1320,7 +1320,7 @@ not specified, then ``obj.__name__`` is used. The optional parameter *module* is the module that contains the given object. - If the module is not specified or is None, then the test finder will attempt + If the module is not specified or is ``None``, then the test finder will attempt to automatically determine the correct module. The object's module is used: * As a default namespace, if *globs* is not specified. diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -96,7 +96,7 @@ Bootstraps ``pip`` into the current or designated environment. *root* specifies an alternative root directory to install relative to. - If *root* is None, then installation uses the default install location + If *root* is ``None``, then installation uses the default install location for the current environment. *upgrade* indicates whether or not to upgrade an existing installation diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -52,7 +52,7 @@ Since a dictionary is used to cache results, the positional and keyword arguments to the function must be hashable. - If *maxsize* is set to None, the LRU feature is disabled and the cache can + If *maxsize* is set to ``None``, the LRU feature is disabled and the cache can grow without bound. The LRU feature performs best when *maxsize* is a power-of-two. diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -280,7 +280,7 @@ .. method:: date_time_string(timestamp=None) - Returns the date and time given by *timestamp* (which must be None or in + Returns the date and time given by *timestamp* (which must be ``None`` or in the format returned by :func:`time.time`), formatted for a message header. If *timestamp* is omitted, it uses the current date and time. diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -128,7 +128,7 @@ Parse an IMAP4 ``INTERNALDATE`` string and return corresponding local time. The return value is a :class:`time.struct_time` tuple or - None if the string has wrong format. + ``None`` if the string has wrong format. .. function:: Int2AP(num) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1056,7 +1056,7 @@ (``__loader__``) The loader to use for loading. For namespace packages this should be - set to None. + set to ``None``. .. attribute:: origin @@ -1064,33 +1064,33 @@ Name of the place from which the module is loaded, e.g. "builtin" for built-in modules and the filename for modules loaded from source. - Normally "origin" should be set, but it may be None (the default) + Normally "origin" should be set, but it may be ``None`` (the default) which indicates it is unspecified. .. attribute:: submodule_search_locations (``__path__``) - List of strings for where to find submodules, if a package (None + List of strings for where to find submodules, if a package (``None`` otherwise). .. attribute:: loader_state Container of extra module-specific data for use during loading (or - None). + ``None``). .. attribute:: cached (``__cached__``) - String for where the compiled module should be stored (or None). + String for where the compiled module should be stored (or ``None``). .. attribute:: parent (``__package__``) (Read-only) Fully-qualified name of the package to which the module - belongs as a submodule (or None). + belongs as a submodule (or ``None``). .. attribute:: has_location diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -407,8 +407,9 @@ (to raise :exc:`TypeError`). If *skipkeys* is false (the default), then it is a :exc:`TypeError` to - attempt encoding of keys that are not str, int, float or None. If - *skipkeys* is true, such items are simply skipped. + attempt encoding of keys that are not :class:`str`, :class:`int`, + :class:`float` or ``None``. If *skipkeys* is true, such items are simply + skipped. If *ensure_ascii* is true (the default), the output is guaranteed to have all incoming non-ASCII characters escaped. If *ensure_ascii* is diff --git a/Doc/library/linecache.rst b/Doc/library/linecache.rst --- a/Doc/library/linecache.rst +++ b/Doc/library/linecache.rst @@ -51,7 +51,7 @@ .. function:: lazycache(filename, module_globals) Capture enough detail about a non-file-based module to permit getting its - lines later via :func:`getline` even if *module_globals* is None in the later + lines later via :func:`getline` even if *module_globals* is ``None`` in the later call. This avoids doing I/O until a line is actually needed, without having to carry the module globals around indefinitely. 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 @@ -138,7 +138,7 @@ across the socket, such that the ``verify`` callable can perform signature verification and/or decryption. The ``verify`` callable is called with a single argument - the bytes received across the socket - and should - return the bytes to be processed, or None to indicate that the bytes should + return the bytes to be processed, or ``None`` to indicate that the bytes should be discarded. The returned bytes could be the same as the passed in bytes (e.g. when only verification is done), or they could be completely different (perhaps if decryption were performed). diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -80,7 +80,7 @@ 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 + :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. @@ -159,7 +159,7 @@ 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 + :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. @@ -275,7 +275,7 @@ 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 + ``'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. diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -296,7 +296,7 @@ Finds the caller's source filename and line number. Returns the filename, line number, function name and stack information as a 4-element tuple. The stack - information is returned as *None* unless *stack_info* is *True*. + information is returned as ``None`` unless *stack_info* is *True*. .. method:: Logger.handle(record) @@ -672,7 +672,7 @@ :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. + or ``None`` if no exception information is available. :param func: The name of the function or method from which the logging call was invoked. :param sinfo: A text string representing stack information from the base of @@ -754,7 +754,7 @@ | | | (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*. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ @@ -1187,7 +1187,7 @@ :lno: The line number in the file where the logging call was made. :msg: The logging message. :args: The arguments for the logging message. - :exc_info: An exception tuple, or None. + :exc_info: An exception tuple, or ``None``. :func: The name of the function or method which invoked the logging call. :sinfo: A stack traceback such as is provided by diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -204,13 +204,13 @@ .. method:: read([n]) Return a :class:`bytes` containing up to *n* bytes starting from the - current file position. If the argument is omitted, *None* or negative, + current file position. If the argument is omitted, ``None`` or negative, return all bytes from the current file position to the end of the mapping. The file position is updated to point after the bytes that were returned. .. versionchanged:: 3.3 - Argument can be omitted or *None*. + Argument can be omitted or ``None``. .. method:: read_byte() diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -948,7 +948,7 @@ Return a context object which has the same attributes as the :mod:`multiprocessing` module. - If *method* is *None* then the default context is returned. + If *method* is ``None`` then the default context is returned. Otherwise *method* should be ``'fork'``, ``'spawn'``, ``'forkserver'``. :exc:`ValueError` is raised if the specified start method is not available. @@ -962,10 +962,10 @@ If the start method has not been fixed and *allow_none* is false, then the start method is fixed to the default and the name is returned. If the start method has not been fixed and *allow_none* - is true then *None* is returned. + is true then ``None`` is returned. The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'`` - or *None*. ``'fork'`` is the default on Unix, while ``'spawn'`` is + or ``None``. ``'fork'`` is the default on Unix, while ``'spawn'`` is the default on Windows. .. versionadded:: 3.4 @@ -2059,7 +2059,7 @@ *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable - unused resources to be freed. The default *maxtasksperchild* is None, which + unused resources to be freed. The default *maxtasksperchild* is ``None``, which means worker processes will live as long as the pool. *context* can be used to specify the context used for starting @@ -2329,7 +2329,7 @@ ``None`` then digest authentication is used. If *authkey* is a byte string then it will be used as the - authentication key; otherwise it must be *None*. + authentication key; otherwise it must be ``None``. If *authkey* is ``None`` and *authenticate* is ``True`` then ``current_process().authkey`` is used as the authentication key. If diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -220,7 +220,7 @@ .. method:: NNTP.login(user=None, password=None, usenetrc=True) Send ``AUTHINFO`` commands with the user name and password. If *user* - and *password* are None and *usenetrc* is true, credentials from + and *password* are ``None`` and *usenetrc* is true, credentials from ``~/.netrc`` will be used if possible. Unless intentionally delayed, login is normally performed during the diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -2026,12 +2026,12 @@ values.ensure_value(attr, value) - If the ``attr`` attribute of ``values`` doesn't exist or is None, then + If the ``attr`` attribute of ``values`` doesn't exist or is ``None``, then ensure_value() first sets it to ``value``, and then returns 'value. This is very handy for actions like ``"extend"``, ``"append"``, and ``"count"``, all of which accumulate data in a variable and expect that variable to be of a certain type (a list for the first two, an integer for the latter). Using :meth:`ensure_value` means that scripts using your action don't have to worry about setting a default value for the option destinations in question; they - can just leave the default as None and :meth:`ensure_value` will take care of + can just leave the default as ``None`` and :meth:`ensure_value` will take care of getting it right when it's needed. diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -257,7 +257,7 @@ executable, similar to a shell, when launching a process. *env*, when specified, should be an environment variable dictionary to lookup the PATH in. - By default, when *env* is None, :data:`environ` is used. + By default, when *env* is ``None``, :data:`environ` is used. .. versionadded:: 3.2 @@ -3814,7 +3814,7 @@ .. function:: cpu_count() - Return the number of CPUs in the system. Returns None if undetermined. + Return the number of CPUs in the system. Returns ``None`` if undetermined. This number is not equivalent to the number of CPUs the current process can use. The number of usable CPUs can be obtained with diff --git a/Doc/library/queue.rst b/Doc/library/queue.rst --- a/Doc/library/queue.rst +++ b/Doc/library/queue.rst @@ -106,7 +106,7 @@ .. method:: Queue.put(item, block=True, timeout=None) Put *item* into the queue. If optional args *block* is true and *timeout* is - None (the default), block if necessary until a free slot is available. If + ``None`` (the default), block if necessary until a free slot is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Full` exception if no free slot was available within that time. Otherwise (*block* is false), put an item on the queue if a free slot is @@ -122,7 +122,7 @@ .. method:: Queue.get(block=True, timeout=None) Remove and return an item from the queue. If optional args *block* is true and - *timeout* is None (the default), block if necessary until an item is available. + *timeout* is ``None`` (the default), block if necessary until an item is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Empty` exception if no item was available within that time. Otherwise (*block* is false), return an item if one is immediately available, diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -470,7 +470,7 @@ Low level interface to kevent - - changelist must be an iterable of kevent object or None + - changelist must be an iterable of kevent object or ``None`` - max_events must be 0 or a positive integer - timeout in seconds (floats possible) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -349,10 +349,10 @@ :rfc:`4954` "initial response" bytes which will be encoded and sent with the ``AUTH`` command as below. If the ``authobject()`` does not support an initial response (e.g. because it requires a challenge), it should return - None when called with ``challenge=None``. If *initial_response_ok* is - false, then ``authobject()`` will not be called first with None. + ``None`` when called with ``challenge=None``. If *initial_response_ok* is + false, then ``authobject()`` will not be called first with ``None``. - If the initial response check returns None, or if *initial_response_ok* is + If the initial response check returns ``None``, or if *initial_response_ok* is false, ``authobject()`` will be called to process the server's challenge response; the *challenge* argument it is passed will be a ``bytes``. It should return ``bytes`` *data* that will be base64 encoded and sent to the @@ -382,8 +382,9 @@ If *keyfile* and *certfile* are provided, these are passed to the :mod:`socket` module's :func:`ssl` function. - Optional *context* parameter is a :class:`ssl.SSLContext` object; This is an alternative to - using a keyfile and a certfile and if specified both *keyfile* and *certfile* should be None. + Optional *context* parameter is a :class:`ssl.SSLContext` object; This is + an alternative to using a keyfile and a certfile and if specified both + *keyfile* and *certfile* should be ``None``. If there has been no previous ``EHLO`` or ``HELO`` command this session, this method tries ESMTP ``EHLO`` first. diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1388,10 +1388,10 @@ Set the value of the given socket option (see the Unix manual page :manpage:`setsockopt(2)`). The needed symbolic constants are defined in the :mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer, - None or a :term:`bytes-like object` representing a buffer. In the later + ``None`` or a :term:`bytes-like object` representing a buffer. In the later case it is up to the caller to ensure that the bytestring contains the proper bits (see the optional built-in module :mod:`struct` for a way to - encode C structures as bytestrings). When value is set to None, + encode C structures as bytestrings). When value is set to ``None``, optlen argument is required. It's equivalent to call setsockopt C function with optval=NULL and optlen=optlen. diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -339,7 +339,7 @@ called as the SQL function. The function can return any of the types supported by SQLite: bytes, str, int, - float and None. + float and ``None``. Example: @@ -356,7 +356,7 @@ final result of the aggregate. The ``finalize`` method can return any of the types supported by SQLite: - bytes, str, int, float and None. + bytes, str, int, float and ``None``. Example: @@ -378,7 +378,7 @@ .. literalinclude:: ../includes/sqlite3/collation_reverse.py - To remove a collation, call ``create_collation`` with None as callable:: + To remove a collation, call ``create_collation`` with ``None`` as callable:: con.create_collation("reverse", None) @@ -939,7 +939,7 @@ (or none at all) via the *isolation_level* parameter to the :func:`connect` call, or via the :attr:`isolation_level` property of connections. -If you want **autocommit mode**, then set :attr:`isolation_level` to None. +If you want **autocommit mode**, then set :attr:`isolation_level` to ``None``. Otherwise leave it at its default, which will result in a plain "BEGIN" statement, or set it to one of SQLite's supported isolation levels: "DEFERRED", diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -464,8 +464,8 @@ :meth:`SSLContext.set_default_verify_paths`. The return value is a :term:`named tuple` ``DefaultVerifyPaths``: - * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist, - * :attr:`capath` - resolved path to capath or None if the directory doesn't exist, + * :attr:`cafile` - resolved path to cafile or ``None`` if the file doesn't exist, + * :attr:`capath` - resolved path to capath or ``None`` if the directory doesn't exist, * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile, * :attr:`openssl_cafile` - hard coded path to a cafile, * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath, diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1756,13 +1756,13 @@ If there is only one argument, it must be a dictionary mapping Unicode ordinals (integers) or characters (strings of length 1) to Unicode ordinals, - strings (of arbitrary lengths) or None. Character keys will then be + strings (of arbitrary lengths) or ``None``. Character keys will then be converted to ordinals. If there are two arguments, they must be strings of equal length, and in the resulting dictionary, each character in x will be mapped to the character at the same position in y. If there is a third argument, it must be a string, - whose characters will be mapped to None in the result. + whose characters will be mapped to ``None`` in the result. .. method:: str.partition(sep) @@ -3760,7 +3760,7 @@ memory as an N-dimensional array. .. versionchanged:: 3.3 - An empty tuple instead of None when ndim = 0. + An empty tuple instead of ``None`` when ndim = 0. .. attribute:: strides @@ -3768,7 +3768,7 @@ access each element for each dimension of the array. .. versionchanged:: 3.3 - An empty tuple instead of None when ndim = 0. + An empty tuple instead of ``None`` when ndim = 0. .. attribute:: suboffsets diff --git a/Doc/library/string.rst b/Doc/library/string.rst --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -446,7 +446,7 @@ In addition to the above presentation types, integers can be formatted with the floating point presentation types listed below (except -``'n'`` and None). When doing so, :func:`float` is used to convert the +``'n'`` and ``None``). When doing so, :func:`float` is used to convert the integer to a floating point number before formatting. The available presentation types for floating point and decimal values are: diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -114,17 +114,17 @@ .. attribute:: stdout Captured stdout from the child process. A bytes sequence, or a string if - :func:`run` was called with an encoding or errors. None if stdout was not + :func:`run` was called with an encoding or errors. ``None`` if stdout was not captured. If you ran the process with ``stderr=subprocess.STDOUT``, stdout and stderr will be combined in this attribute, and :attr:`stderr` will be - None. + ``None``. .. attribute:: stderr Captured stderr from the child process. A bytes sequence, or a string if - :func:`run` was called with an encoding or errors. None if stderr was not + :func:`run` was called with an encoding or errors. ``None`` if stderr was not captured. .. method:: check_returncode() diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1209,7 +1209,7 @@ .. note:: Under some conditions ``stdin``, ``stdout`` and ``stderr`` as well as the original values ``__stdin__``, ``__stdout__`` and ``__stderr__`` can be - None. It is usually the case for Windows GUI apps that aren't connected + ``None``. It is usually the case for Windows GUI apps that aren't connected to a console and Python apps started with :program:`pythonw`. diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -398,7 +398,7 @@ A context manager that creates a temporary directory at *path* and yields the directory. - If *path* is None, the temporary directory is created using + If *path* is ``None``, the temporary directory is created using :func:`tempfile.mkdtemp`. If *quiet* is ``False``, the context manager raises an exception on error. Otherwise, if *path* is specified and cannot be created, only a warning is issued. @@ -421,7 +421,7 @@ The context manager creates a temporary directory in the current directory with name *name* before temporarily changing the current - working directory. If *name* is None, the temporary directory is + working directory. If *name* is ``None``, the temporary directory is created using :func:`tempfile.mkdtemp`. If *quiet* is ``False`` and it is not possible to create or change diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -714,7 +714,7 @@ without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true. - When invoked with a *timeout* other than None, it will block for at + When invoked with a *timeout* other than ``None``, it will block for at most *timeout* seconds. If acquire does not complete successfully in that interval, return false. Return true otherwise. @@ -854,8 +854,8 @@ Create a timer that will run *function* with arguments *args* and keyword arguments *kwargs*, after *interval* seconds have passed. - If *args* is None (the default) then an empty list will be used. - If *kwargs* is None (the default) then an empty dict will be used. + If *args* is ``None`` (the default) then an empty list will be used. + If *kwargs* is ``None`` (the default) then an empty dict will be used. .. versionchanged:: 3.3 changed from a factory function to a class. diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -145,7 +145,7 @@ 100, 1000, ...) up to a maximum of one billion, until the time taken is at least 0.2 second, or the maximum is reached. - If *callback* is given and is not *None*, it will be called after + If *callback* is given and is not ``None``, it will be called after each trial with two arguments: ``callback(number, time_taken)``. .. versionadded:: 3.6 diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -1404,7 +1404,7 @@ Layouts ^^^^^^^ -A layout can be just None, if it takes no options, or a dict of +A layout can be just ``None``, if it takes no options, or a dict of options specifying how to arrange the element. The layout mechanism uses a simplified version of the pack geometry manager: given an initial cavity, each element is allocated a parcel. Valid diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -549,7 +549,7 @@ :param n: an integer (or ``None``) - Delete all or first/last *n* of turtle's stamps. If *n* is None, delete + Delete all or first/last *n* of turtle's stamps. If *n* is ``None``, delete all stamps, if *n* > 0 delete first *n* stamps, else if *n* < 0 delete last *n* stamps. @@ -1799,7 +1799,7 @@ Pop up a dialog window for input of a string. Parameter title is the title of the dialog window, propmt is a text mostly describing what information to input. - Return the string input. If the dialog is canceled, return None. :: + Return the string input. If the dialog is canceled, return ``None``. :: >>> screen.textinput("NIM", "Name of first player:") @@ -1819,7 +1819,7 @@ The number input must be in the range minval .. maxval if these are given. If not, a hint is issued and the dialog remains open for correction. - Return the number input. If the dialog is canceled, return None. :: + Return the number input. If the dialog is canceled, return ``None``. :: >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000) @@ -1984,10 +1984,10 @@ :param height: if an integer, the height in pixels, if a float, a fraction of the screen; default is 75% of screen :param startx: if positive, starting position in pixels from the left - edge of the screen, if negative from the right edge, if None, + edge of the screen, if negative from the right edge, if ``None``, center window horizontally :param starty: if positive, starting position in pixels from the top - edge of the screen, if negative from the bottom edge, if None, + edge of the screen, if negative from the bottom edge, if ``None``, center window vertically .. doctest:: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -718,7 +718,7 @@ This is often the same as ``obj.__annotations__``, but it handles forward references encoded as string literals, and if necessary - adds ``Optional[t]`` if a default value equal to None is set. + adds ``Optional[t]`` if a default value equal to ``None`` is set. .. decorator:: overload diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -244,7 +244,7 @@ .. versionadded:: 3.5 - * *wraps*: Item for the mock object to wrap. If *wraps* is not None then + * *wraps*: Item for the mock object to wrap. If *wraps* is not ``None`` then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -868,7 +868,7 @@ .. method:: assertIsNone(expr, msg=None) assertIsNotNone(expr, msg=None) - Test that *expr* is (or is not) None. + Test that *expr* is (or is not) ``None``. .. versionadded:: 3.1 @@ -1340,7 +1340,7 @@ methods that delegate to it), :meth:`assertDictEqual` and :meth:`assertMultiLineEqual`. - Setting ``maxDiff`` to None means that there is no maximum length of + Setting ``maxDiff`` to ``None`` means that there is no maximum length of diffs. .. versionadded:: 3.2 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 @@ -495,7 +495,7 @@ .. attribute:: Request.data - The entity body for the request, or None if not specified. + The entity body for the request, or ``None`` if not specified. .. versionchanged:: 3.4 Changing value of :attr:`Request.data` now deletes "Content-Length" diff --git a/Doc/library/xml.sax.reader.rst b/Doc/library/xml.sax.reader.rst --- a/Doc/library/xml.sax.reader.rst +++ b/Doc/library/xml.sax.reader.rst @@ -308,7 +308,7 @@ Get the byte stream for this input source. The getEncoding method will return the character encoding for this byte stream, - or None if unknown. + or ``None`` if unknown. .. method:: InputSource.setCharacterStream(charfile) diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -121,7 +121,7 @@ the archive will be written to that file. * If it is an open file object, the archive will be written to that file object, which must be open for writing in bytes mode. - * If the target is omitted (or None), the source must be a directory + * If the target is omitted (or ``None``), the source must be a directory and the target will be a file with the same name as the source, with a ``.pyz`` extension added. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -771,7 +771,7 @@ dictionary containing the class's namespace; :attr:`~class.__bases__` is a tuple (possibly empty or a singleton) containing the base classes, in the order of their occurrence in the base class list; :attr:`__doc__` is the - class's documentation string, or None if undefined; + class's documentation string, or ``None`` if undefined; :attr:`__annotations__` (optional) is a dictionary containing :term:`variable annotations ` collected during class body execution. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1439,7 +1439,7 @@ be a :term:`keyword argument`. The user-supplied filter function accepts a :class:`~tarfile.TarInfo` object and returns an updated :class:`~tarfile.TarInfo` object, or if it wants the file to be excluded, the -function can return *None*:: +function can return ``None``:: >>> import tarfile, glob @@ -1488,7 +1488,7 @@ syntax. The :func:`ast.literal_eval` function serves as a secure alternative to the builtin :func:`eval` function which is easily abused. Python 3.2 adds :class:`bytes` and :class:`set` literals to the list of supported types: -strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. +strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and ``None``. :: 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 @@ -182,7 +182,7 @@ * The maximum number of dimensions is officially limited to 64. * The representation of empty shape, strides and suboffsets is now - an empty tuple instead of None. + an empty tuple instead of ``None``. * Accessing a memoryview element with format 'B' (unsigned bytes) now returns an integer (in accordance with the struct module syntax). diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -161,7 +161,7 @@ * :ref:`Safe object finalization ` (:pep:`442`). * Leveraging :pep:`442`, in most cases :ref:`module globals are no longer set - to None during finalization ` (:issue:`18214`). + to ``None`` during finalization ` (:issue:`18214`). * :ref:`Configurable memory allocators ` (:pep:`445`). * :ref:`Argument Clinic ` (:pep:`436`). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:10 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Mark_up_True_and_False_as_literal_text_instead_of_bold=2E?= Message-ID: <20161019134610.110892.47346.D0CC018F@psf.io> https://hg.python.org/cpython/rev/b7df6c09ddf9 changeset: 104556:b7df6c09ddf9 branch: 2.7 parent: 104552:cef2373f31bb user: Serhiy Storchaka date: Wed Oct 19 16:43:18 2016 +0300 summary: Issue #19795: Mark up True and False as literal text instead of bold. files: Doc/howto/logging.rst | 6 +++--- Doc/library/argparse.rst | 2 +- Doc/library/cmath.rst | 4 ++-- Doc/library/shelve.rst | 2 +- Doc/library/subprocess.rst | 4 ++-- Doc/library/urllib.rst | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -464,7 +464,7 @@ 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*.) +attribute of a logger to ``False``.) .. _handler-basic: @@ -737,10 +737,10 @@ For Python 2.x, the behaviour is as follows: -* If *logging.raiseExceptions* is *False* (production mode), the event is +* If *logging.raiseExceptions* is ``False`` (production mode), the event is silently dropped. -* If *logging.raiseExceptions* is *True* (development mode), a message +* If *logging.raiseExceptions* is ``True`` (development mode), a message 'No handlers could be found for logger X.Y.Z' is printed once. .. _library-config: diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -695,7 +695,7 @@ * ``'store_true'`` and ``'store_false'`` - These are special cases of ``'store_const'`` using for storing the values ``True`` and ``False`` - respectively. In addition, they create default values of *False* and *True* + respectively. In addition, they create default values of ``False`` and ``True`` respectively. For example:: >>> parser = argparse.ArgumentParser() diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -207,7 +207,7 @@ .. function:: isinf(x) - Return *True* if the real or the imaginary part of x is positive + Return ``True`` if the real or the imaginary part of x is positive or negative infinity. .. versionadded:: 2.6 @@ -215,7 +215,7 @@ .. function:: isnan(x) - Return *True* if the real or imaginary part of x is not a number (NaN). + Return ``True`` if the real or imaginary part of x is not a number (NaN). .. versionadded:: 2.6 diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -35,7 +35,7 @@ Because of Python semantics, a shelf cannot know when a mutable persistent-dictionary entry is modified. By default modified objects are written *only* when assigned to the shelf (see :ref:`shelve-example`). If the - optional *writeback* parameter is set to *True*, all entries accessed are also + optional *writeback* parameter is set to ``True``, all entries accessed are also cached in memory, and written back on :meth:`~Shelf.sync` and :meth:`~Shelf.close`; this can make it handier to mutate mutable entries in the persistent dictionary, but, if many entries are accessed, it can consume diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -320,8 +320,8 @@ manner described in :ref:`converting-argument-sequence`. This is because the underlying ``CreateProcess()`` operates on strings. - The *shell* argument (which defaults to *False*) specifies whether to use - the shell as the program to execute. If *shell* is *True*, it is + The *shell* argument (which defaults to ``False``) specifies whether to use + the shell as the program to execute. If *shell* is ``True``, it is recommended to pass *args* as a string rather than as a sequence. On Unix with ``shell=True``, the shell defaults to :file:`/bin/sh`. If diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst --- a/Doc/library/urllib.rst +++ b/Doc/library/urllib.rst @@ -263,7 +263,7 @@ two-element tuples is used as the *query* argument, the first element of each tuple is a key and the second is a value. The value element in itself can be a sequence and in that case, if the optional parameter *doseq* is - evaluates to *True*, individual ``key=value`` pairs separated by ``'&'`` are + evaluates to ``True``, individual ``key=value`` pairs separated by ``'&'`` are generated for each element of the value sequence for the key. The order of parameters in the encoded string will match the order of parameter tuples in the sequence. The :mod:`urlparse` module provides the functions -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:10 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319795=3A_Mark_up_None_as_literal_text=2E?= Message-ID: <20161019134609.11782.91653.A77D4F08@psf.io> https://hg.python.org/cpython/rev/5f997b3cb59c changeset: 104555:5f997b3cb59c parent: 104551:465c09937e85 parent: 104554:2e97ed8e7e3c user: Serhiy Storchaka date: Wed Oct 19 16:39:36 2016 +0300 summary: Issue #19795: Mark up None as literal text. files: Doc/c-api/none.rst | 6 +++--- Doc/c-api/unicode.rst | 8 ++++---- Doc/howto/descriptor.rst | 2 +- Doc/howto/logging.rst | 2 +- Doc/howto/sorting.rst | 2 +- Doc/library/argparse.rst | 10 +++++----- Doc/library/asyncio-protocol.rst | 4 ++-- Doc/library/asyncore.rst | 2 +- Doc/library/bdb.rst | 2 +- Doc/library/code.rst | 2 +- Doc/library/collections.rst | 4 ++-- Doc/library/dis.rst | 10 +++++----- Doc/library/doctest.rst | 4 ++-- Doc/library/ensurepip.rst | 2 +- Doc/library/functools.rst | 2 +- Doc/library/http.server.rst | 2 +- Doc/library/imaplib.rst | 2 +- Doc/library/importlib.rst | 12 ++++++------ Doc/library/json.rst | 5 +++-- Doc/library/linecache.rst | 2 +- Doc/library/logging.config.rst | 2 +- Doc/library/logging.handlers.rst | 6 +++--- Doc/library/logging.rst | 8 ++++---- Doc/library/mmap.rst | 4 ++-- Doc/library/multiprocessing.rst | 10 +++++----- Doc/library/nntplib.rst | 2 +- Doc/library/optparse.rst | 4 ++-- Doc/library/os.rst | 4 ++-- Doc/library/queue.rst | 4 ++-- Doc/library/select.rst | 2 +- Doc/library/smtplib.rst | 11 ++++++----- Doc/library/socket.rst | 4 ++-- Doc/library/sqlite3.rst | 8 ++++---- Doc/library/ssl.rst | 4 ++-- Doc/library/stdtypes.rst | 8 ++++---- Doc/library/string.rst | 2 +- Doc/library/subprocess.rst | 6 +++--- Doc/library/sys.rst | 2 +- Doc/library/test.rst | 4 ++-- Doc/library/threading.rst | 6 +++--- Doc/library/timeit.rst | 2 +- Doc/library/tkinter.ttk.rst | 2 +- Doc/library/turtle.rst | 10 +++++----- Doc/library/typing.rst | 2 +- Doc/library/unittest.mock.rst | 2 +- Doc/library/unittest.rst | 4 ++-- Doc/library/urllib.request.rst | 2 +- Doc/library/xml.sax.reader.rst | 2 +- Doc/library/zipapp.rst | 2 +- Doc/reference/datamodel.rst | 2 +- Doc/whatsnew/3.2.rst | 4 ++-- Doc/whatsnew/3.3.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- 53 files changed, 113 insertions(+), 111 deletions(-) diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -2,8 +2,8 @@ .. _noneobject: -The None Object ---------------- +The ``None`` Object +------------------- .. index:: object: None @@ -23,4 +23,4 @@ .. c:macro:: Py_RETURN_NONE Properly handle returning :c:data:`Py_None` from within a C function (that is, - increment the reference count of None and return it.) + increment the reference count of ``None`` and return it.) 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 @@ -1415,11 +1415,11 @@ decode characters. Decoding mappings must map single string characters to single Unicode -characters, integers (which are then interpreted as Unicode ordinals) or None +characters, integers (which are then interpreted as Unicode ordinals) or ``None`` (meaning "undefined mapping" and causing an error). Encoding mappings must map single Unicode characters to single string -characters, integers (which are then interpreted as Latin-1 ordinals) or None +characters, integers (which are then interpreted as Latin-1 ordinals) or ``None`` (meaning "undefined mapping" and causing an error). The mapping objects provided must only support the __getitem__ mapping @@ -1460,7 +1460,7 @@ *NULL* when an exception was raised by the codec. The *mapping* table must map Unicode ordinal integers to Unicode ordinal - integers or None (causing deletion of the character). + integers or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a @@ -1577,7 +1577,7 @@ resulting Unicode object. The mapping table must map Unicode ordinal integers to Unicode ordinal integers - or None (causing deletion of the character). + or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -302,7 +302,7 @@ While they could have been implemented that way, the actual C implementation of :c:type:`PyMethod_Type` in :source:`Objects/classobject.c` is a single object with two different representations depending on whether the :attr:`im_self` -field is set or is *NULL* (the C equivalent of *None*). +field is set or is *NULL* (the C equivalent of ``None``). Likewise, the effects of calling a method object depend on the :attr:`im_self` field. If set (meaning bound), the original function (stored in the diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -764,7 +764,7 @@ The handler's level is set to ``WARNING``, so all events at this and greater severities will be output. -To obtain the pre-3.2 behaviour, ``logging.lastResort`` can be set to *None*. +To obtain the pre-3.2 behaviour, ``logging.lastResort`` can be set to ``None``. .. _library-config: diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -24,7 +24,7 @@ [1, 2, 3, 4, 5] You can also use the :meth:`list.sort` method. It modifies the list -in-place (and returns *None* to avoid confusion). Usually it's less convenient +in-place (and returns ``None`` to avoid confusion). Usually it's less convenient than :func:`sorted` - but if you don't need the original list, it's slightly more efficient. diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1552,7 +1552,7 @@ positional arguments * description - description for the sub-parser group in help output, by - default None + default ``None`` * prog - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the @@ -1565,12 +1565,12 @@ encountered at the command line * dest_ - name of the attribute under which sub-command name will be - stored; by default None and no value is stored - - * help_ - help for sub-parser group in help output, by default None + stored; by default ``None`` and no value is stored + + * help_ - help for sub-parser group in help output, by default ``None`` * metavar_ - string presenting available sub-commands in help; by default it - is None and presents sub-commands in form {cmd1, cmd2, ..} + is ``None`` and presents sub-commands in form {cmd1, cmd2, ..} Some example usage:: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -372,10 +372,10 @@ (for example by calling :meth:`write_eof`, if the other end also uses asyncio). - This method may return a false value (including None), in which case + This method may return a false value (including ``None``), in which case the transport will close itself. Conversely, if this method returns a true value, closing the transport is up to the protocol. Since the - default implementation returns None, it implicitly closes the connection. + default implementation returns ``None``, it implicitly closes the connection. .. note:: Some transports such as SSL don't support half-closed connections, diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -57,7 +57,7 @@ Enter a polling loop that terminates after count passes or all open channels have been closed. All arguments are optional. The *count* - parameter defaults to None, resulting in the loop terminating only when all + parameter defaults to ``None``, resulting in the loop terminating only when all channels have been closed. The *timeout* argument sets the timeout parameter for the appropriate :func:`~select.select` or :func:`~select.poll` call, measured in seconds; the default is 30 seconds. The *use_poll* diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -241,7 +241,7 @@ .. method:: set_continue() Stop only at breakpoints or when finished. If there are no breakpoints, - set the system trace function to None. + set the system trace function to ``None``. .. method:: set_quit() diff --git a/Doc/library/code.rst b/Doc/library/code.rst --- a/Doc/library/code.rst +++ b/Doc/library/code.rst @@ -150,7 +150,7 @@ The optional *exitmsg* argument specifies an exit message printed when exiting. Pass the empty string to suppress the exit message. If *exitmsg* is not given or - None, a default message is printed. + ``None``, a default message is printed. .. versionchanged:: 3.4 To suppress printing any banner, pass an empty string. diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -412,7 +412,7 @@ position of the underlying data representation. - If *maxlen* is not specified or is *None*, deques may grow to an + If *maxlen* is not specified or is ``None``, deques may grow to an arbitrary length. Otherwise, the deque is bounded to the specified maximum length. Once a bounded length deque is full, when new items are added, a corresponding number of items are discarded from the opposite end. Bounded @@ -520,7 +520,7 @@ .. attribute:: maxlen - Maximum size of a deque or *None* if unbounded. + Maximum size of a deque or ``None`` if unbounded. .. versionadded:: 3.1 diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -56,12 +56,12 @@ notably :func:`get_instructions`, as iterating over a :class:`Bytecode` instance yields the bytecode operations as :class:`Instruction` instances. - If *first_line* is not None, it indicates the line number that should be + If *first_line* is not ``None``, it indicates the line number that should be reported for the first source line in the disassembled code. Otherwise, the source line information (if any) is taken directly from the disassembled code object. - If *current_offset* is not None, it refers to an instruction offset in the + If *current_offset* is not ``None``, it refers to an instruction offset in the disassembled code. Setting this means :meth:`.dis` will display a "current instruction" marker against the specified opcode. @@ -197,7 +197,7 @@ The iterator generates a series of :class:`Instruction` named tuples giving the details of each operation in the supplied code. - If *first_line* is not None, it indicates the line number that should be + If *first_line* is not ``None``, it indicates the line number that should be reported for the first source line in the disassembled code. Otherwise, the source line information (if any) is taken directly from the disassembled code object. @@ -249,7 +249,7 @@ .. data:: arg - numeric argument to operation (if any), otherwise None + numeric argument to operation (if any), otherwise ``None`` .. data:: argval @@ -269,7 +269,7 @@ .. data:: starts_line - line started by this opcode (if any), otherwise None + line started by this opcode (if any), otherwise ``None`` .. data:: is_jump_target diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1215,7 +1215,7 @@ .. attribute:: docstring - The string that the test was extracted from, or 'None' if the string is + The string that the test was extracted from, or ``None`` if the string is unavailable, or if the test was not extracted from a string. @@ -1320,7 +1320,7 @@ not specified, then ``obj.__name__`` is used. The optional parameter *module* is the module that contains the given object. - If the module is not specified or is None, then the test finder will attempt + If the module is not specified or is ``None``, then the test finder will attempt to automatically determine the correct module. The object's module is used: * As a default namespace, if *globs* is not specified. diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -96,7 +96,7 @@ Bootstraps ``pip`` into the current or designated environment. *root* specifies an alternative root directory to install relative to. - If *root* is None, then installation uses the default install location + If *root* is ``None``, then installation uses the default install location for the current environment. *upgrade* indicates whether or not to upgrade an existing installation diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -52,7 +52,7 @@ Since a dictionary is used to cache results, the positional and keyword arguments to the function must be hashable. - If *maxsize* is set to None, the LRU feature is disabled and the cache can + If *maxsize* is set to ``None``, the LRU feature is disabled and the cache can grow without bound. The LRU feature performs best when *maxsize* is a power-of-two. diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -280,7 +280,7 @@ .. method:: date_time_string(timestamp=None) - Returns the date and time given by *timestamp* (which must be None or in + Returns the date and time given by *timestamp* (which must be ``None`` or in the format returned by :func:`time.time`), formatted for a message header. If *timestamp* is omitted, it uses the current date and time. diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -128,7 +128,7 @@ Parse an IMAP4 ``INTERNALDATE`` string and return corresponding local time. The return value is a :class:`time.struct_time` tuple or - None if the string has wrong format. + ``None`` if the string has wrong format. .. function:: Int2AP(num) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1056,7 +1056,7 @@ (``__loader__``) The loader to use for loading. For namespace packages this should be - set to None. + set to ``None``. .. attribute:: origin @@ -1064,33 +1064,33 @@ Name of the place from which the module is loaded, e.g. "builtin" for built-in modules and the filename for modules loaded from source. - Normally "origin" should be set, but it may be None (the default) + Normally "origin" should be set, but it may be ``None`` (the default) which indicates it is unspecified. .. attribute:: submodule_search_locations (``__path__``) - List of strings for where to find submodules, if a package (None + List of strings for where to find submodules, if a package (``None`` otherwise). .. attribute:: loader_state Container of extra module-specific data for use during loading (or - None). + ``None``). .. attribute:: cached (``__cached__``) - String for where the compiled module should be stored (or None). + String for where the compiled module should be stored (or ``None``). .. attribute:: parent (``__package__``) (Read-only) Fully-qualified name of the package to which the module - belongs as a submodule (or None). + belongs as a submodule (or ``None``). .. attribute:: has_location diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -407,8 +407,9 @@ (to raise :exc:`TypeError`). If *skipkeys* is false (the default), then it is a :exc:`TypeError` to - attempt encoding of keys that are not str, int, float or None. If - *skipkeys* is true, such items are simply skipped. + attempt encoding of keys that are not :class:`str`, :class:`int`, + :class:`float` or ``None``. If *skipkeys* is true, such items are simply + skipped. If *ensure_ascii* is true (the default), the output is guaranteed to have all incoming non-ASCII characters escaped. If *ensure_ascii* is diff --git a/Doc/library/linecache.rst b/Doc/library/linecache.rst --- a/Doc/library/linecache.rst +++ b/Doc/library/linecache.rst @@ -51,7 +51,7 @@ .. function:: lazycache(filename, module_globals) Capture enough detail about a non-file-based module to permit getting its - lines later via :func:`getline` even if *module_globals* is None in the later + lines later via :func:`getline` even if *module_globals* is ``None`` in the later call. This avoids doing I/O until a line is actually needed, without having to carry the module globals around indefinitely. 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 @@ -138,7 +138,7 @@ across the socket, such that the ``verify`` callable can perform signature verification and/or decryption. The ``verify`` callable is called with a single argument - the bytes received across the socket - and should - return the bytes to be processed, or None to indicate that the bytes should + return the bytes to be processed, or ``None`` to indicate that the bytes should be discarded. The returned bytes could be the same as the passed in bytes (e.g. when only verification is done), or they could be completely different (perhaps if decryption were performed). diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -80,7 +80,7 @@ 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 + :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. @@ -159,7 +159,7 @@ 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 + :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. @@ -275,7 +275,7 @@ 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 + ``'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. diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -296,7 +296,7 @@ Finds the caller's source filename and line number. Returns the filename, line number, function name and stack information as a 4-element tuple. The stack - information is returned as *None* unless *stack_info* is *True*. + information is returned as ``None`` unless *stack_info* is *True*. .. method:: Logger.handle(record) @@ -672,7 +672,7 @@ :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. + or ``None`` if no exception information is available. :param func: The name of the function or method from which the logging call was invoked. :param sinfo: A text string representing stack information from the base of @@ -754,7 +754,7 @@ | | | (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*. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ @@ -1187,7 +1187,7 @@ :lno: The line number in the file where the logging call was made. :msg: The logging message. :args: The arguments for the logging message. - :exc_info: An exception tuple, or None. + :exc_info: An exception tuple, or ``None``. :func: The name of the function or method which invoked the logging call. :sinfo: A stack traceback such as is provided by diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -204,13 +204,13 @@ .. method:: read([n]) Return a :class:`bytes` containing up to *n* bytes starting from the - current file position. If the argument is omitted, *None* or negative, + current file position. If the argument is omitted, ``None`` or negative, return all bytes from the current file position to the end of the mapping. The file position is updated to point after the bytes that were returned. .. versionchanged:: 3.3 - Argument can be omitted or *None*. + Argument can be omitted or ``None``. .. method:: read_byte() diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -948,7 +948,7 @@ Return a context object which has the same attributes as the :mod:`multiprocessing` module. - If *method* is *None* then the default context is returned. + If *method* is ``None`` then the default context is returned. Otherwise *method* should be ``'fork'``, ``'spawn'``, ``'forkserver'``. :exc:`ValueError` is raised if the specified start method is not available. @@ -962,10 +962,10 @@ If the start method has not been fixed and *allow_none* is false, then the start method is fixed to the default and the name is returned. If the start method has not been fixed and *allow_none* - is true then *None* is returned. + is true then ``None`` is returned. The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'`` - or *None*. ``'fork'`` is the default on Unix, while ``'spawn'`` is + or ``None``. ``'fork'`` is the default on Unix, while ``'spawn'`` is the default on Windows. .. versionadded:: 3.4 @@ -2059,7 +2059,7 @@ *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable - unused resources to be freed. The default *maxtasksperchild* is None, which + unused resources to be freed. The default *maxtasksperchild* is ``None``, which means worker processes will live as long as the pool. *context* can be used to specify the context used for starting @@ -2329,7 +2329,7 @@ ``None`` then digest authentication is used. If *authkey* is a byte string then it will be used as the - authentication key; otherwise it must be *None*. + authentication key; otherwise it must be ``None``. If *authkey* is ``None`` and *authenticate* is ``True`` then ``current_process().authkey`` is used as the authentication key. If diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -220,7 +220,7 @@ .. method:: NNTP.login(user=None, password=None, usenetrc=True) Send ``AUTHINFO`` commands with the user name and password. If *user* - and *password* are None and *usenetrc* is true, credentials from + and *password* are ``None`` and *usenetrc* is true, credentials from ``~/.netrc`` will be used if possible. Unless intentionally delayed, login is normally performed during the diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -2026,12 +2026,12 @@ values.ensure_value(attr, value) - If the ``attr`` attribute of ``values`` doesn't exist or is None, then + If the ``attr`` attribute of ``values`` doesn't exist or is ``None``, then ensure_value() first sets it to ``value``, and then returns 'value. This is very handy for actions like ``"extend"``, ``"append"``, and ``"count"``, all of which accumulate data in a variable and expect that variable to be of a certain type (a list for the first two, an integer for the latter). Using :meth:`ensure_value` means that scripts using your action don't have to worry about setting a default value for the option destinations in question; they - can just leave the default as None and :meth:`ensure_value` will take care of + can just leave the default as ``None`` and :meth:`ensure_value` will take care of getting it right when it's needed. diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -257,7 +257,7 @@ executable, similar to a shell, when launching a process. *env*, when specified, should be an environment variable dictionary to lookup the PATH in. - By default, when *env* is None, :data:`environ` is used. + By default, when *env* is ``None``, :data:`environ` is used. .. versionadded:: 3.2 @@ -3814,7 +3814,7 @@ .. function:: cpu_count() - Return the number of CPUs in the system. Returns None if undetermined. + Return the number of CPUs in the system. Returns ``None`` if undetermined. This number is not equivalent to the number of CPUs the current process can use. The number of usable CPUs can be obtained with diff --git a/Doc/library/queue.rst b/Doc/library/queue.rst --- a/Doc/library/queue.rst +++ b/Doc/library/queue.rst @@ -106,7 +106,7 @@ .. method:: Queue.put(item, block=True, timeout=None) Put *item* into the queue. If optional args *block* is true and *timeout* is - None (the default), block if necessary until a free slot is available. If + ``None`` (the default), block if necessary until a free slot is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Full` exception if no free slot was available within that time. Otherwise (*block* is false), put an item on the queue if a free slot is @@ -122,7 +122,7 @@ .. method:: Queue.get(block=True, timeout=None) Remove and return an item from the queue. If optional args *block* is true and - *timeout* is None (the default), block if necessary until an item is available. + *timeout* is ``None`` (the default), block if necessary until an item is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Empty` exception if no item was available within that time. Otherwise (*block* is false), return an item if one is immediately available, diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -470,7 +470,7 @@ Low level interface to kevent - - changelist must be an iterable of kevent object or None + - changelist must be an iterable of kevent object or ``None`` - max_events must be 0 or a positive integer - timeout in seconds (floats possible) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -349,10 +349,10 @@ :rfc:`4954` "initial response" bytes which will be encoded and sent with the ``AUTH`` command as below. If the ``authobject()`` does not support an initial response (e.g. because it requires a challenge), it should return - None when called with ``challenge=None``. If *initial_response_ok* is - false, then ``authobject()`` will not be called first with None. + ``None`` when called with ``challenge=None``. If *initial_response_ok* is + false, then ``authobject()`` will not be called first with ``None``. - If the initial response check returns None, or if *initial_response_ok* is + If the initial response check returns ``None``, or if *initial_response_ok* is false, ``authobject()`` will be called to process the server's challenge response; the *challenge* argument it is passed will be a ``bytes``. It should return ``bytes`` *data* that will be base64 encoded and sent to the @@ -382,8 +382,9 @@ If *keyfile* and *certfile* are provided, these are passed to the :mod:`socket` module's :func:`ssl` function. - Optional *context* parameter is a :class:`ssl.SSLContext` object; This is an alternative to - using a keyfile and a certfile and if specified both *keyfile* and *certfile* should be None. + Optional *context* parameter is a :class:`ssl.SSLContext` object; This is + an alternative to using a keyfile and a certfile and if specified both + *keyfile* and *certfile* should be ``None``. If there has been no previous ``EHLO`` or ``HELO`` command this session, this method tries ESMTP ``EHLO`` first. diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1400,10 +1400,10 @@ Set the value of the given socket option (see the Unix manual page :manpage:`setsockopt(2)`). The needed symbolic constants are defined in the :mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer, - None or a :term:`bytes-like object` representing a buffer. In the later + ``None`` or a :term:`bytes-like object` representing a buffer. In the later case it is up to the caller to ensure that the bytestring contains the proper bits (see the optional built-in module :mod:`struct` for a way to - encode C structures as bytestrings). When value is set to None, + encode C structures as bytestrings). When value is set to ``None``, optlen argument is required. It's equivalent to call setsockopt C function with optval=NULL and optlen=optlen. diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -339,7 +339,7 @@ called as the SQL function. The function can return any of the types supported by SQLite: bytes, str, int, - float and None. + float and ``None``. Example: @@ -356,7 +356,7 @@ final result of the aggregate. The ``finalize`` method can return any of the types supported by SQLite: - bytes, str, int, float and None. + bytes, str, int, float and ``None``. Example: @@ -378,7 +378,7 @@ .. literalinclude:: ../includes/sqlite3/collation_reverse.py - To remove a collation, call ``create_collation`` with None as callable:: + To remove a collation, call ``create_collation`` with ``None`` as callable:: con.create_collation("reverse", None) @@ -939,7 +939,7 @@ (or none at all) via the *isolation_level* parameter to the :func:`connect` call, or via the :attr:`isolation_level` property of connections. -If you want **autocommit mode**, then set :attr:`isolation_level` to None. +If you want **autocommit mode**, then set :attr:`isolation_level` to ``None``. Otherwise leave it at its default, which will result in a plain "BEGIN" statement, or set it to one of SQLite's supported isolation levels: "DEFERRED", diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -464,8 +464,8 @@ :meth:`SSLContext.set_default_verify_paths`. The return value is a :term:`named tuple` ``DefaultVerifyPaths``: - * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist, - * :attr:`capath` - resolved path to capath or None if the directory doesn't exist, + * :attr:`cafile` - resolved path to cafile or ``None`` if the file doesn't exist, + * :attr:`capath` - resolved path to capath or ``None`` if the directory doesn't exist, * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile, * :attr:`openssl_cafile` - hard coded path to a cafile, * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath, diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1756,13 +1756,13 @@ If there is only one argument, it must be a dictionary mapping Unicode ordinals (integers) or characters (strings of length 1) to Unicode ordinals, - strings (of arbitrary lengths) or None. Character keys will then be + strings (of arbitrary lengths) or ``None``. Character keys will then be converted to ordinals. If there are two arguments, they must be strings of equal length, and in the resulting dictionary, each character in x will be mapped to the character at the same position in y. If there is a third argument, it must be a string, - whose characters will be mapped to None in the result. + whose characters will be mapped to ``None`` in the result. .. method:: str.partition(sep) @@ -3760,7 +3760,7 @@ memory as an N-dimensional array. .. versionchanged:: 3.3 - An empty tuple instead of None when ndim = 0. + An empty tuple instead of ``None`` when ndim = 0. .. attribute:: strides @@ -3768,7 +3768,7 @@ access each element for each dimension of the array. .. versionchanged:: 3.3 - An empty tuple instead of None when ndim = 0. + An empty tuple instead of ``None`` when ndim = 0. .. attribute:: suboffsets diff --git a/Doc/library/string.rst b/Doc/library/string.rst --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -446,7 +446,7 @@ In addition to the above presentation types, integers can be formatted with the floating point presentation types listed below (except -``'n'`` and None). When doing so, :func:`float` is used to convert the +``'n'`` and ``None``). When doing so, :func:`float` is used to convert the integer to a floating point number before formatting. The available presentation types for floating point and decimal values are: diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -114,17 +114,17 @@ .. attribute:: stdout Captured stdout from the child process. A bytes sequence, or a string if - :func:`run` was called with an encoding or errors. None if stdout was not + :func:`run` was called with an encoding or errors. ``None`` if stdout was not captured. If you ran the process with ``stderr=subprocess.STDOUT``, stdout and stderr will be combined in this attribute, and :attr:`stderr` will be - None. + ``None``. .. attribute:: stderr Captured stderr from the child process. A bytes sequence, or a string if - :func:`run` was called with an encoding or errors. None if stderr was not + :func:`run` was called with an encoding or errors. ``None`` if stderr was not captured. .. method:: check_returncode() diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1209,7 +1209,7 @@ .. note:: Under some conditions ``stdin``, ``stdout`` and ``stderr`` as well as the original values ``__stdin__``, ``__stdout__`` and ``__stderr__`` can be - None. It is usually the case for Windows GUI apps that aren't connected + ``None``. It is usually the case for Windows GUI apps that aren't connected to a console and Python apps started with :program:`pythonw`. diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -398,7 +398,7 @@ A context manager that creates a temporary directory at *path* and yields the directory. - If *path* is None, the temporary directory is created using + If *path* is ``None``, the temporary directory is created using :func:`tempfile.mkdtemp`. If *quiet* is ``False``, the context manager raises an exception on error. Otherwise, if *path* is specified and cannot be created, only a warning is issued. @@ -421,7 +421,7 @@ The context manager creates a temporary directory in the current directory with name *name* before temporarily changing the current - working directory. If *name* is None, the temporary directory is + working directory. If *name* is ``None``, the temporary directory is created using :func:`tempfile.mkdtemp`. If *quiet* is ``False`` and it is not possible to create or change diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -714,7 +714,7 @@ without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true. - When invoked with a *timeout* other than None, it will block for at + When invoked with a *timeout* other than ``None``, it will block for at most *timeout* seconds. If acquire does not complete successfully in that interval, return false. Return true otherwise. @@ -854,8 +854,8 @@ Create a timer that will run *function* with arguments *args* and keyword arguments *kwargs*, after *interval* seconds have passed. - If *args* is None (the default) then an empty list will be used. - If *kwargs* is None (the default) then an empty dict will be used. + If *args* is ``None`` (the default) then an empty list will be used. + If *kwargs* is ``None`` (the default) then an empty dict will be used. .. versionchanged:: 3.3 changed from a factory function to a class. diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -145,7 +145,7 @@ 100, 1000, ...) up to a maximum of one billion, until the time taken is at least 0.2 second, or the maximum is reached. - If *callback* is given and is not *None*, it will be called after + If *callback* is given and is not ``None``, it will be called after each trial with two arguments: ``callback(number, time_taken)``. .. versionadded:: 3.6 diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -1404,7 +1404,7 @@ Layouts ^^^^^^^ -A layout can be just None, if it takes no options, or a dict of +A layout can be just ``None``, if it takes no options, or a dict of options specifying how to arrange the element. The layout mechanism uses a simplified version of the pack geometry manager: given an initial cavity, each element is allocated a parcel. Valid diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -549,7 +549,7 @@ :param n: an integer (or ``None``) - Delete all or first/last *n* of turtle's stamps. If *n* is None, delete + Delete all or first/last *n* of turtle's stamps. If *n* is ``None``, delete all stamps, if *n* > 0 delete first *n* stamps, else if *n* < 0 delete last *n* stamps. @@ -1799,7 +1799,7 @@ Pop up a dialog window for input of a string. Parameter title is the title of the dialog window, propmt is a text mostly describing what information to input. - Return the string input. If the dialog is canceled, return None. :: + Return the string input. If the dialog is canceled, return ``None``. :: >>> screen.textinput("NIM", "Name of first player:") @@ -1819,7 +1819,7 @@ The number input must be in the range minval .. maxval if these are given. If not, a hint is issued and the dialog remains open for correction. - Return the number input. If the dialog is canceled, return None. :: + Return the number input. If the dialog is canceled, return ``None``. :: >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000) @@ -1984,10 +1984,10 @@ :param height: if an integer, the height in pixels, if a float, a fraction of the screen; default is 75% of screen :param startx: if positive, starting position in pixels from the left - edge of the screen, if negative from the right edge, if None, + edge of the screen, if negative from the right edge, if ``None``, center window horizontally :param starty: if positive, starting position in pixels from the top - edge of the screen, if negative from the bottom edge, if None, + edge of the screen, if negative from the bottom edge, if ``None``, center window vertically .. doctest:: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -718,7 +718,7 @@ This is often the same as ``obj.__annotations__``, but it handles forward references encoded as string literals, and if necessary - adds ``Optional[t]`` if a default value equal to None is set. + adds ``Optional[t]`` if a default value equal to ``None`` is set. .. decorator:: overload diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -244,7 +244,7 @@ .. versionadded:: 3.5 - * *wraps*: Item for the mock object to wrap. If *wraps* is not None then + * *wraps*: Item for the mock object to wrap. If *wraps* is not ``None`` then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -868,7 +868,7 @@ .. method:: assertIsNone(expr, msg=None) assertIsNotNone(expr, msg=None) - Test that *expr* is (or is not) None. + Test that *expr* is (or is not) ``None``. .. versionadded:: 3.1 @@ -1340,7 +1340,7 @@ methods that delegate to it), :meth:`assertDictEqual` and :meth:`assertMultiLineEqual`. - Setting ``maxDiff`` to None means that there is no maximum length of + Setting ``maxDiff`` to ``None`` means that there is no maximum length of diffs. .. versionadded:: 3.2 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 @@ -495,7 +495,7 @@ .. attribute:: Request.data - The entity body for the request, or None if not specified. + The entity body for the request, or ``None`` if not specified. .. versionchanged:: 3.4 Changing value of :attr:`Request.data` now deletes "Content-Length" diff --git a/Doc/library/xml.sax.reader.rst b/Doc/library/xml.sax.reader.rst --- a/Doc/library/xml.sax.reader.rst +++ b/Doc/library/xml.sax.reader.rst @@ -308,7 +308,7 @@ Get the byte stream for this input source. The getEncoding method will return the character encoding for this byte stream, - or None if unknown. + or ``None`` if unknown. .. method:: InputSource.setCharacterStream(charfile) diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -121,7 +121,7 @@ the archive will be written to that file. * If it is an open file object, the archive will be written to that file object, which must be open for writing in bytes mode. - * If the target is omitted (or None), the source must be a directory + * If the target is omitted (or ``None``), the source must be a directory and the target will be a file with the same name as the source, with a ``.pyz`` extension added. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -771,7 +771,7 @@ dictionary containing the class's namespace; :attr:`~class.__bases__` is a tuple (possibly empty or a singleton) containing the base classes, in the order of their occurrence in the base class list; :attr:`__doc__` is the - class's documentation string, or None if undefined; + class's documentation string, or ``None`` if undefined; :attr:`__annotations__` (optional) is a dictionary containing :term:`variable annotations ` collected during class body execution. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1439,7 +1439,7 @@ be a :term:`keyword argument`. The user-supplied filter function accepts a :class:`~tarfile.TarInfo` object and returns an updated :class:`~tarfile.TarInfo` object, or if it wants the file to be excluded, the -function can return *None*:: +function can return ``None``:: >>> import tarfile, glob @@ -1488,7 +1488,7 @@ syntax. The :func:`ast.literal_eval` function serves as a secure alternative to the builtin :func:`eval` function which is easily abused. Python 3.2 adds :class:`bytes` and :class:`set` literals to the list of supported types: -strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. +strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and ``None``. :: 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 @@ -182,7 +182,7 @@ * The maximum number of dimensions is officially limited to 64. * The representation of empty shape, strides and suboffsets is now - an empty tuple instead of None. + an empty tuple instead of ``None``. * Accessing a memoryview element with format 'B' (unsigned bytes) now returns an integer (in accordance with the struct module syntax). diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -161,7 +161,7 @@ * :ref:`Safe object finalization ` (:pep:`442`). * Leveraging :pep:`442`, in most cases :ref:`module globals are no longer set - to None during finalization ` (:issue:`18214`). + to ``None`` during finalization ` (:issue:`18214`). * :ref:`Configurable memory allocators ` (:pep:`445`). * :ref:`Argument Clinic ` (:pep:`436`). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2319795=3A_Mark_up_True_and_False_as_literal_text_inste?= =?utf-8?q?ad_of_bold=2E?= Message-ID: <20161019134610.25114.62934.7F32F72A@psf.io> https://hg.python.org/cpython/rev/91992ea3c6b1 changeset: 104558:91992ea3c6b1 branch: 3.6 parent: 104554:2e97ed8e7e3c parent: 104557:477a82ec81fc user: Serhiy Storchaka date: Wed Oct 19 16:44:47 2016 +0300 summary: Issue #19795: Mark up True and False as literal text instead of bold. files: Doc/howto/logging.rst | 6 +++--- Doc/library/logging.rst | 2 +- Doc/library/shelve.rst | 2 +- Doc/library/subprocess.rst | 4 ++-- Doc/library/urllib.parse.rst | 2 +- Doc/library/xml.etree.elementtree.rst | 2 +- Doc/library/xml.sax.utils.rst | 4 ++-- Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.2.rst | 8 ++++---- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -464,7 +464,7 @@ 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*.) +attribute of a logger to ``False``.) .. _handler-basic: @@ -747,10 +747,10 @@ For versions of Python prior to 3.2, the behaviour is as follows: -* If *logging.raiseExceptions* is *False* (production mode), the event is +* If *logging.raiseExceptions* is ``False`` (production mode), the event is silently dropped. -* If *logging.raiseExceptions* is *True* (development mode), a message +* If *logging.raiseExceptions* is ``True`` (development mode), a message 'No handlers could be found for logger X.Y.Z' is printed once. In Python 3.2 and later, the behaviour is as follows: diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -296,7 +296,7 @@ Finds the caller's source filename and line number. Returns the filename, line number, function name and stack information as a 4-element tuple. The stack - information is returned as ``None`` unless *stack_info* is *True*. + information is returned as ``None`` unless *stack_info* is ``True``. .. method:: Logger.handle(record) diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -31,7 +31,7 @@ Because of Python semantics, a shelf cannot know when a mutable persistent-dictionary entry is modified. By default modified objects are written *only* when assigned to the shelf (see :ref:`shelve-example`). If the - optional *writeback* parameter is set to *True*, all entries accessed are also + optional *writeback* parameter is set to ``True``, all entries accessed are also cached in memory, and written back on :meth:`~Shelf.sync` and :meth:`~Shelf.close`; this can make it handier to mutate mutable entries in the persistent dictionary, but, if many entries are accessed, it can consume diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -361,8 +361,8 @@ manner described in :ref:`converting-argument-sequence`. This is because the underlying ``CreateProcess()`` operates on strings. - The *shell* argument (which defaults to *False*) specifies whether to use - the shell as the program to execute. If *shell* is *True*, it is + The *shell* argument (which defaults to ``False``) specifies whether to use + the shell as the program to execute. If *shell* is ``True``, it is recommended to pass *args* as a string rather than as a sequence. On POSIX with ``shell=True``, the shell defaults to :file:`/bin/sh`. If diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -553,7 +553,7 @@ When a sequence of two-element tuples is used as the *query* argument, the first element of each tuple is a key and the second is a value. The value element in itself can be a sequence and in that case, if - the optional parameter *doseq* is evaluates to *True*, individual + the optional parameter *doseq* is evaluates to ``True``, individual ``key=value`` pairs separated by ``'&'`` are generated for each element of the value sequence for the key. The order of parameters in the encoded string will match the order of parameter tuples in the sequence. diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -928,7 +928,7 @@ *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). The keyword-only *short_empty_elements* parameter controls the formatting - of elements that contain no content. If *True* (the default), they are + of elements that contain no content. If ``True`` (the default), they are emitted as a single self-closed tag, otherwise they are emitted as a pair of start/end tags. diff --git a/Doc/library/xml.sax.utils.rst b/Doc/library/xml.sax.utils.rst --- a/Doc/library/xml.sax.utils.rst +++ b/Doc/library/xml.sax.utils.rst @@ -63,8 +63,8 @@ should be a file-like object which will default to *sys.stdout*. *encoding* is the encoding of the output stream which defaults to ``'iso-8859-1'``. *short_empty_elements* controls the formatting of elements that contain no - content: if *False* (the default) they are emitted as a pair of start/end - tags, if set to *True* they are emitted as a single self-closed tag. + content: if ``False`` (the default) they are emitted as a pair of start/end + tags, if set to ``True`` they are emitted as a single self-closed tag. .. versionadded:: 3.2 The *short_empty_elements* parameter. diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -548,5 +548,5 @@ * The automatic name remapping in the pickle module for protocol 2 or lower can make Python 3.1 pickles unreadable in Python 3.0. One solution is to use - protocol 3. Another solution is to set the *fix_imports* option to **False**. + protocol 3. Another solution is to set the *fix_imports* option to *``False``*. See the discussion above for more details. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1001,13 +1001,13 @@ after 1900. The new supported year range is from 1000 to 9999 inclusive. * Whenever a two-digit year is used in a time tuple, the interpretation has been - governed by :attr:`time.accept2dyear`. The default is *True* which means that + governed by :attr:`time.accept2dyear`. The default is ``True`` which means that for a two-digit year, the century is guessed according to the POSIX rules governing the ``%y`` strptime format. Starting with Py3.2, use of the century guessing heuristic will emit a :exc:`DeprecationWarning`. Instead, it is recommended that - :attr:`time.accept2dyear` be set to *False* so that large date ranges + :attr:`time.accept2dyear` be set to ``False`` so that large date ranges can be used without guesswork:: >>> import time, warnings @@ -1043,7 +1043,7 @@ C99 standard. The :func:`~math.isfinite` function provides a reliable and fast way to detect -special values. It returns *True* for regular numbers and *False* for *Nan* or +special values. It returns ``True`` for regular numbers and ``False`` for *Nan* or *Infinity*: >>> from math import isfinite @@ -1193,7 +1193,7 @@ The use of filters has been simplified. Instead of creating a :class:`~logging.Filter` object, the predicate can be any Python callable that -returns *True* or *False*. +returns ``True`` or ``False``. There were a number of other improvements that add flexibility and simplify configuration. See the module documentation for a full listing of changes in -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319795=3A_Mark_up_True_and_False_as_literal_text?= =?utf-8?q?_instead_of_bold=2E?= Message-ID: <20161019134610.25114.16642.E6E5B807@psf.io> https://hg.python.org/cpython/rev/8cc9ad294ea9 changeset: 104559:8cc9ad294ea9 parent: 104555:5f997b3cb59c parent: 104558:91992ea3c6b1 user: Serhiy Storchaka date: Wed Oct 19 16:45:05 2016 +0300 summary: Issue #19795: Mark up True and False as literal text instead of bold. files: Doc/howto/logging.rst | 6 +++--- Doc/library/logging.rst | 2 +- Doc/library/shelve.rst | 2 +- Doc/library/subprocess.rst | 4 ++-- Doc/library/urllib.parse.rst | 2 +- Doc/library/xml.etree.elementtree.rst | 2 +- Doc/library/xml.sax.utils.rst | 4 ++-- Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.2.rst | 8 ++++---- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -464,7 +464,7 @@ 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*.) +attribute of a logger to ``False``.) .. _handler-basic: @@ -747,10 +747,10 @@ For versions of Python prior to 3.2, the behaviour is as follows: -* If *logging.raiseExceptions* is *False* (production mode), the event is +* If *logging.raiseExceptions* is ``False`` (production mode), the event is silently dropped. -* If *logging.raiseExceptions* is *True* (development mode), a message +* If *logging.raiseExceptions* is ``True`` (development mode), a message 'No handlers could be found for logger X.Y.Z' is printed once. In Python 3.2 and later, the behaviour is as follows: diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -296,7 +296,7 @@ Finds the caller's source filename and line number. Returns the filename, line number, function name and stack information as a 4-element tuple. The stack - information is returned as ``None`` unless *stack_info* is *True*. + information is returned as ``None`` unless *stack_info* is ``True``. .. method:: Logger.handle(record) diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -31,7 +31,7 @@ Because of Python semantics, a shelf cannot know when a mutable persistent-dictionary entry is modified. By default modified objects are written *only* when assigned to the shelf (see :ref:`shelve-example`). If the - optional *writeback* parameter is set to *True*, all entries accessed are also + optional *writeback* parameter is set to ``True``, all entries accessed are also cached in memory, and written back on :meth:`~Shelf.sync` and :meth:`~Shelf.close`; this can make it handier to mutate mutable entries in the persistent dictionary, but, if many entries are accessed, it can consume diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -361,8 +361,8 @@ manner described in :ref:`converting-argument-sequence`. This is because the underlying ``CreateProcess()`` operates on strings. - The *shell* argument (which defaults to *False*) specifies whether to use - the shell as the program to execute. If *shell* is *True*, it is + The *shell* argument (which defaults to ``False``) specifies whether to use + the shell as the program to execute. If *shell* is ``True``, it is recommended to pass *args* as a string rather than as a sequence. On POSIX with ``shell=True``, the shell defaults to :file:`/bin/sh`. If diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -553,7 +553,7 @@ When a sequence of two-element tuples is used as the *query* argument, the first element of each tuple is a key and the second is a value. The value element in itself can be a sequence and in that case, if - the optional parameter *doseq* is evaluates to *True*, individual + the optional parameter *doseq* is evaluates to ``True``, individual ``key=value`` pairs separated by ``'&'`` are generated for each element of the value sequence for the key. The order of parameters in the encoded string will match the order of parameter tuples in the sequence. diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -928,7 +928,7 @@ *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). The keyword-only *short_empty_elements* parameter controls the formatting - of elements that contain no content. If *True* (the default), they are + of elements that contain no content. If ``True`` (the default), they are emitted as a single self-closed tag, otherwise they are emitted as a pair of start/end tags. diff --git a/Doc/library/xml.sax.utils.rst b/Doc/library/xml.sax.utils.rst --- a/Doc/library/xml.sax.utils.rst +++ b/Doc/library/xml.sax.utils.rst @@ -63,8 +63,8 @@ should be a file-like object which will default to *sys.stdout*. *encoding* is the encoding of the output stream which defaults to ``'iso-8859-1'``. *short_empty_elements* controls the formatting of elements that contain no - content: if *False* (the default) they are emitted as a pair of start/end - tags, if set to *True* they are emitted as a single self-closed tag. + content: if ``False`` (the default) they are emitted as a pair of start/end + tags, if set to ``True`` they are emitted as a single self-closed tag. .. versionadded:: 3.2 The *short_empty_elements* parameter. diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -548,5 +548,5 @@ * The automatic name remapping in the pickle module for protocol 2 or lower can make Python 3.1 pickles unreadable in Python 3.0. One solution is to use - protocol 3. Another solution is to set the *fix_imports* option to **False**. + protocol 3. Another solution is to set the *fix_imports* option to *``False``*. See the discussion above for more details. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1001,13 +1001,13 @@ after 1900. The new supported year range is from 1000 to 9999 inclusive. * Whenever a two-digit year is used in a time tuple, the interpretation has been - governed by :attr:`time.accept2dyear`. The default is *True* which means that + governed by :attr:`time.accept2dyear`. The default is ``True`` which means that for a two-digit year, the century is guessed according to the POSIX rules governing the ``%y`` strptime format. Starting with Py3.2, use of the century guessing heuristic will emit a :exc:`DeprecationWarning`. Instead, it is recommended that - :attr:`time.accept2dyear` be set to *False* so that large date ranges + :attr:`time.accept2dyear` be set to ``False`` so that large date ranges can be used without guesswork:: >>> import time, warnings @@ -1043,7 +1043,7 @@ C99 standard. The :func:`~math.isfinite` function provides a reliable and fast way to detect -special values. It returns *True* for regular numbers and *False* for *Nan* or +special values. It returns ``True`` for regular numbers and ``False`` for *Nan* or *Infinity*: >>> from math import isfinite @@ -1193,7 +1193,7 @@ The use of filters has been simplified. Instead of creating a :class:`~logging.Filter` object, the predicate can be any Python callable that -returns *True* or *False*. +returns ``True`` or ``False``. There were a number of other improvements that add flexibility and simplify configuration. See the module documentation for a full listing of changes in -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Mark_up_True_and_False_as_literal_text_instead_of_bold=2E?= Message-ID: <20161019134610.9443.48445.CA7DE5AE@psf.io> https://hg.python.org/cpython/rev/477a82ec81fc changeset: 104557:477a82ec81fc branch: 3.5 parent: 104553:a8d5b433bb36 user: Serhiy Storchaka date: Wed Oct 19 16:43:42 2016 +0300 summary: Issue #19795: Mark up True and False as literal text instead of bold. files: Doc/howto/logging.rst | 6 +++--- Doc/library/logging.rst | 2 +- Doc/library/shelve.rst | 2 +- Doc/library/subprocess.rst | 4 ++-- Doc/library/urllib.parse.rst | 2 +- Doc/library/xml.etree.elementtree.rst | 2 +- Doc/library/xml.sax.utils.rst | 4 ++-- Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.2.rst | 8 ++++---- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -464,7 +464,7 @@ 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*.) +attribute of a logger to ``False``.) .. _handler-basic: @@ -747,10 +747,10 @@ For versions of Python prior to 3.2, the behaviour is as follows: -* If *logging.raiseExceptions* is *False* (production mode), the event is +* If *logging.raiseExceptions* is ``False`` (production mode), the event is silently dropped. -* If *logging.raiseExceptions* is *True* (development mode), a message +* If *logging.raiseExceptions* is ``True`` (development mode), a message 'No handlers could be found for logger X.Y.Z' is printed once. In Python 3.2 and later, the behaviour is as follows: diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -296,7 +296,7 @@ Finds the caller's source filename and line number. Returns the filename, line number, function name and stack information as a 4-element tuple. The stack - information is returned as ``None`` unless *stack_info* is *True*. + information is returned as ``None`` unless *stack_info* is ``True``. .. method:: Logger.handle(record) diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -31,7 +31,7 @@ Because of Python semantics, a shelf cannot know when a mutable persistent-dictionary entry is modified. By default modified objects are written *only* when assigned to the shelf (see :ref:`shelve-example`). If the - optional *writeback* parameter is set to *True*, all entries accessed are also + optional *writeback* parameter is set to ``True``, all entries accessed are also cached in memory, and written back on :meth:`~Shelf.sync` and :meth:`~Shelf.close`; this can make it handier to mutate mutable entries in the persistent dictionary, but, if many entries are accessed, it can consume diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -347,8 +347,8 @@ manner described in :ref:`converting-argument-sequence`. This is because the underlying ``CreateProcess()`` operates on strings. - The *shell* argument (which defaults to *False*) specifies whether to use - the shell as the program to execute. If *shell* is *True*, it is + The *shell* argument (which defaults to ``False``) specifies whether to use + the shell as the program to execute. If *shell* is ``True``, it is recommended to pass *args* as a string rather than as a sequence. On POSIX with ``shell=True``, the shell defaults to :file:`/bin/sh`. If diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -543,7 +543,7 @@ When a sequence of two-element tuples is used as the *query* argument, the first element of each tuple is a key and the second is a value. The value element in itself can be a sequence and in that case, if - the optional parameter *doseq* is evaluates to *True*, individual + the optional parameter *doseq* is evaluates to ``True``, individual ``key=value`` pairs separated by ``'&'`` are generated for each element of the value sequence for the key. The order of parameters in the encoded string will match the order of parameter tuples in the sequence. diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -928,7 +928,7 @@ *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). The keyword-only *short_empty_elements* parameter controls the formatting - of elements that contain no content. If *True* (the default), they are + of elements that contain no content. If ``True`` (the default), they are emitted as a single self-closed tag, otherwise they are emitted as a pair of start/end tags. diff --git a/Doc/library/xml.sax.utils.rst b/Doc/library/xml.sax.utils.rst --- a/Doc/library/xml.sax.utils.rst +++ b/Doc/library/xml.sax.utils.rst @@ -63,8 +63,8 @@ should be a file-like object which will default to *sys.stdout*. *encoding* is the encoding of the output stream which defaults to ``'iso-8859-1'``. *short_empty_elements* controls the formatting of elements that contain no - content: if *False* (the default) they are emitted as a pair of start/end - tags, if set to *True* they are emitted as a single self-closed tag. + content: if ``False`` (the default) they are emitted as a pair of start/end + tags, if set to ``True`` they are emitted as a single self-closed tag. .. versionadded:: 3.2 The *short_empty_elements* parameter. diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -548,5 +548,5 @@ * The automatic name remapping in the pickle module for protocol 2 or lower can make Python 3.1 pickles unreadable in Python 3.0. One solution is to use - protocol 3. Another solution is to set the *fix_imports* option to **False**. + protocol 3. Another solution is to set the *fix_imports* option to *``False``*. See the discussion above for more details. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1001,13 +1001,13 @@ after 1900. The new supported year range is from 1000 to 9999 inclusive. * Whenever a two-digit year is used in a time tuple, the interpretation has been - governed by :attr:`time.accept2dyear`. The default is *True* which means that + governed by :attr:`time.accept2dyear`. The default is ``True`` which means that for a two-digit year, the century is guessed according to the POSIX rules governing the ``%y`` strptime format. Starting with Py3.2, use of the century guessing heuristic will emit a :exc:`DeprecationWarning`. Instead, it is recommended that - :attr:`time.accept2dyear` be set to *False* so that large date ranges + :attr:`time.accept2dyear` be set to ``False`` so that large date ranges can be used without guesswork:: >>> import time, warnings @@ -1043,7 +1043,7 @@ C99 standard. The :func:`~math.isfinite` function provides a reliable and fast way to detect -special values. It returns *True* for regular numbers and *False* for *Nan* or +special values. It returns ``True`` for regular numbers and ``False`` for *Nan* or *Infinity*: >>> from math import isfinite @@ -1193,7 +1193,7 @@ The use of filters has been simplified. Instead of creating a :class:`~logging.Filter` object, the predicate can be any Python callable that -returns *True* or *False*. +returns ``True`` or ``False``. There were a number of other improvements that add flexibility and simplify configuration. See the module documentation for a full listing of changes in -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:46:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 13:46:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Mark_up_None_as_literal_text=2E?= Message-ID: <20161019134606.27356.49716.F537F69B@psf.io> https://hg.python.org/cpython/rev/cef2373f31bb changeset: 104552:cef2373f31bb branch: 2.7 parent: 104535:3b22c99535d0 user: Serhiy Storchaka date: Wed Oct 19 16:29:10 2016 +0300 summary: Issue #19795: Mark up None as literal text. files: Doc/c-api/none.rst | 4 ++-- Doc/c-api/unicode.rst | 8 ++++---- Doc/howto/descriptor.rst | 2 +- Doc/howto/sorting.rst | 2 +- Doc/library/argparse.rst | 8 ++++---- Doc/library/asyncore.rst | 2 +- Doc/library/bdb.rst | 2 +- Doc/library/collections.rst | 4 ++-- Doc/library/doctest.rst | 4 ++-- Doc/library/ensurepip.rst | 2 +- Doc/library/formatter.rst | 2 +- Doc/library/imaplib.rst | 2 +- Doc/library/inspect.rst | 7 ++++--- Doc/library/json.rst | 2 +- Doc/library/logging.handlers.rst | 6 +++--- Doc/library/logging.rst | 14 ++++++++++++-- Doc/library/multiprocessing.rst | 4 ++-- Doc/library/optparse.rst | 4 ++-- Doc/library/queue.rst | 4 ++-- Doc/library/select.rst | 2 +- Doc/library/sqlite3.rst | 8 ++++---- Doc/library/ssl.rst | 4 ++-- Doc/library/string.rst | 2 +- Doc/library/ttk.rst | 2 +- Doc/library/turtle.rst | 6 +++--- Doc/library/unittest.rst | 4 ++-- Doc/library/xml.etree.elementtree.rst | 6 +++--- Doc/library/xml.sax.reader.rst | 2 +- Doc/reference/datamodel.rst | 4 ++-- 29 files changed, 67 insertions(+), 56 deletions(-) diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -2,8 +2,8 @@ .. _noneobject: -The None Object ---------------- +The ``None`` Object +------------------- .. index:: object: None 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 @@ -856,11 +856,11 @@ decode characters. Decoding mappings must map single string characters to single Unicode -characters, integers (which are then interpreted as Unicode ordinals) or None +characters, integers (which are then interpreted as Unicode ordinals) or ``None`` (meaning "undefined mapping" and causing an error). Encoding mappings must map single Unicode characters to single string -characters, integers (which are then interpreted as Latin-1 ordinals) or None +characters, integers (which are then interpreted as Latin-1 ordinals) or ``None`` (meaning "undefined mapping" and causing an error). The mapping objects provided must only support the __getitem__ mapping @@ -917,7 +917,7 @@ *NULL* when an exception was raised by the codec. The *mapping* table must map Unicode ordinal integers to Unicode ordinal - integers or None (causing deletion of the character). + integers or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a @@ -1019,7 +1019,7 @@ resulting Unicode object. The mapping table must map Unicode ordinal integers to Unicode ordinal integers - or None (causing deletion of the character). + or ``None`` (causing deletion of the character). Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -308,7 +308,7 @@ While they could have been implemented that way, the actual C implementation of :c:type:`PyMethod_Type` in :source:`Objects/classobject.c` is a single object with two different representations depending on whether the :attr:`im_self` -field is set or is *NULL* (the C equivalent of *None*). +field is set or is *NULL* (the C equivalent of ``None``). Likewise, the effects of calling a method object depend on the :attr:`im_self` field. If set (meaning bound), the original function (stored in the diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -24,7 +24,7 @@ [1, 2, 3, 4, 5] You can also use the :meth:`list.sort` method of a list. It modifies the list -in-place (and returns *None* to avoid confusion). Usually it's less convenient +in-place (and returns ``None`` to avoid confusion). Usually it's less convenient than :func:`sorted` - but if you don't need the original list, it's slightly more efficient. diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1500,7 +1500,7 @@ positional arguments * description - description for the sub-parser group in help output, by - default None + default ``None`` * prog - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the @@ -1513,12 +1513,12 @@ encountered at the command line * dest_ - name of the attribute under which sub-command name will be - stored; by default None and no value is stored + stored; by default ``None`` and no value is stored - * help_ - help for sub-parser group in help output, by default None + * help_ - help for sub-parser group in help output, by default ``None`` * metavar_ - string presenting available sub-commands in help; by default it - is None and presents sub-commands in form {cmd1, cmd2, ..} + is ``None`` and presents sub-commands in form {cmd1, cmd2, ..} Some example usage:: diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -51,7 +51,7 @@ Enter a polling loop that terminates after count passes or all open channels have been closed. All arguments are optional. The *count* - parameter defaults to None, resulting in the loop terminating only when all + parameter defaults to ``None``, resulting in the loop terminating only when all channels have been closed. The *timeout* argument sets the timeout parameter for the appropriate :func:`~select.select` or :func:`~select.poll` call, measured in seconds; the default is 30 seconds. The *use_poll* diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -233,7 +233,7 @@ .. method:: set_continue() Stop only at breakpoints or when finished. If there are no breakpoints, - set the system trace function to None. + set the system trace function to ``None``. .. method:: set_quit() diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -237,7 +237,7 @@ .. versionadded:: 2.4 - If *maxlen* is not specified or is *None*, deques may grow to an + If *maxlen* is not specified or is ``None``, deques may grow to an arbitrary length. Otherwise, the deque is bounded to the specified maximum length. Once a bounded length deque is full, when new items are added, a corresponding number of items are discarded from the opposite end. Bounded @@ -321,7 +321,7 @@ .. attribute:: maxlen - Maximum size of a deque or *None* if unbounded. + Maximum size of a deque or ``None`` if unbounded. .. versionadded:: 2.7 diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1273,7 +1273,7 @@ .. attribute:: docstring - The string that the test was extracted from, or 'None' if the string is + The string that the test was extracted from, or ``None`` if the string is unavailable, or if the test was not extracted from a string. @@ -1381,7 +1381,7 @@ not specified, then ``obj.__name__`` is used. The optional parameter *module* is the module that contains the given object. - If the module is not specified or is None, then the test finder will attempt + If the module is not specified or is ``None``, then the test finder will attempt to automatically determine the correct module. The object's module is used: * As a default namespace, if *globs* is not specified. diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -94,7 +94,7 @@ Bootstraps ``pip`` into the current or designated environment. *root* specifies an alternative root directory to install relative to. - If *root* is None, then installation uses the default install location + If *root* is ``None``, then installation uses the default install location for the current environment. *upgrade* indicates whether or not to upgrade an existing installation diff --git a/Doc/library/formatter.rst b/Doc/library/formatter.rst --- a/Doc/library/formatter.rst +++ b/Doc/library/formatter.rst @@ -344,7 +344,7 @@ .. class:: DumbWriter(file=None, maxcol=72) Simple writer class which writes output on the file object passed in as *file* - or, if *file* is None, on standard output. The output is simply word-wrapped + or, if *file* is ``None``, on standard output. The output is simply word-wrapped to the number of columns specified by *maxcol*. This class is suitable for reflowing a sequence of paragraphs. diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -90,7 +90,7 @@ Parse an IMAP4 ``INTERNALDATE`` string and return corresponding local time. The return value is a :class:`time.struct_time` instance or - None if the string has wrong format. + ``None`` if the string has wrong format. .. function:: Int2AP(num) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -95,8 +95,9 @@ | | gi_code | code object | | +-----------+-----------------+---------------------------+-------+ | | gi_frame | frame object or possibly | | -| | | None once the generator | | -| | | has been exhausted | | +| | | ``None`` once the | | +| | | generator has been | | +| | | exhausted | | +-----------+-----------------+---------------------------+-------+ | | gi_running | set to 1 when generator | | | | | is executing, 0 otherwise | | @@ -478,7 +479,7 @@ four things is returned: ``(args, varargs, keywords, defaults)``. *args* is a list of the argument names (it may contain nested lists). *varargs* and *keywords* are the names of the ``*`` and ``**`` arguments or - ``None``. *defaults* is a tuple of default argument values or None if there + ``None``. *defaults* is a tuple of default argument values or ``None`` if there are no default arguments; if this tuple has *n* elements, they correspond to the last *n* elements listed in *args*. diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -403,7 +403,7 @@ (to raise :exc:`TypeError`). If *skipkeys* is false (the default), then it is a :exc:`TypeError` to - attempt encoding of keys that are not str, int, long, float or None. If + attempt encoding of keys that are not str, int, long, float or ``None``. If *skipkeys* is true, such items are simply skipped. If *ensure_ascii* is true (the default), all non-ASCII characters in the diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -74,7 +74,7 @@ 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 + :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. @@ -154,7 +154,7 @@ 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 + :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. @@ -178,7 +178,7 @@ 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 + ``'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. diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -588,7 +588,7 @@ :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. + or ``None`` if no exception information is available. :param func: The name of the function or method from which the logging call was invoked. @@ -636,7 +636,7 @@ | | | (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*. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ @@ -1026,4 +1026,14 @@ package available from this site is suitable for use with Python 1.5.2, 2.1.x and 2.2.x, which do not include the :mod:`logging` package in the standard library. +<<<<<<< +======= + :lno: The line number in the file where the logging call was made. + :msg: The logging message. + :args: The arguments for the logging message. + :exc_info: An exception tuple, or ``None``. + :func: The name of the function or method which invoked the logging + call. + :sinfo: A stack traceback such as is provided by +>>>>>>> diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1800,7 +1800,7 @@ .. versionadded:: 2.7 *maxtasksperchild* is the number of tasks a worker process can complete before it will exit and be replaced with a fresh worker process, to enable - unused resources to be freed. The default *maxtasksperchild* is None, which + unused resources to be freed. The default *maxtasksperchild* is ``None``, which means worker processes will live as long as the pool. .. note:: @@ -2017,7 +2017,7 @@ ``None`` then digest authentication is used. If *authkey* is a string then it will be used as the authentication key; - otherwise it must be *None*. + otherwise it must be ``None``. If *authkey* is ``None`` and *authenticate* is ``True`` then ``current_process().authkey`` is used as the authentication key. If diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -2028,12 +2028,12 @@ values.ensure_value(attr, value) - If the ``attr`` attribute of ``values`` doesn't exist or is None, then + If the ``attr`` attribute of ``values`` doesn't exist or is ``None``, then ensure_value() first sets it to ``value``, and then returns 'value. This is very handy for actions like ``"extend"``, ``"append"``, and ``"count"``, all of which accumulate data in a variable and expect that variable to be of a certain type (a list for the first two, an integer for the latter). Using :meth:`ensure_value` means that scripts using your action don't have to worry about setting a default value for the option destinations in question; they - can just leave the default as None and :meth:`ensure_value` will take care of + can just leave the default as ``None`` and :meth:`ensure_value` will take care of getting it right when it's needed. diff --git a/Doc/library/queue.rst b/Doc/library/queue.rst --- a/Doc/library/queue.rst +++ b/Doc/library/queue.rst @@ -113,7 +113,7 @@ .. method:: Queue.put(item[, block[, timeout]]) Put *item* into the queue. If optional args *block* is true and *timeout* is - None (the default), block if necessary until a free slot is available. If + ``None`` (the default), block if necessary until a free slot is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Full` exception if no free slot was available within that time. Otherwise (*block* is false), put an item on the queue if a free slot is @@ -132,7 +132,7 @@ .. method:: Queue.get([block[, timeout]]) Remove and return an item from the queue. If optional args *block* is true and - *timeout* is None (the default), block if necessary until an item is available. + *timeout* is ``None`` (the default), block if necessary until an item is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :exc:`Empty` exception if no item was available within that time. Otherwise (*block* is false), return an item if one is immediately available, diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -295,7 +295,7 @@ Low level interface to kevent - - changelist must be an iterable of kevent object or None + - changelist must be an iterable of kevent object or ``None`` - max_events must be 0 or a positive integer - timeout in seconds (floats possible) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -308,7 +308,7 @@ as the SQL function. The function can return any of the types supported by SQLite: unicode, str, int, - long, float, buffer and None. + long, float, buffer and ``None``. Example: @@ -324,7 +324,7 @@ final result of the aggregate. The ``finalize`` method can return any of the types supported by SQLite: - unicode, str, int, long, float, buffer and None. + unicode, str, int, long, float, buffer and ``None``. Example: @@ -346,7 +346,7 @@ .. literalinclude:: ../includes/sqlite3/collation_reverse.py - To remove a collation, call ``create_collation`` with None as callable:: + To remove a collation, call ``create_collation`` with ``None`` as callable:: con.create_collation("reverse", None) @@ -868,7 +868,7 @@ (or none at all) via the *isolation_level* parameter to the :func:`connect` call, or via the :attr:`isolation_level` property of connections. -If you want **autocommit mode**, then set :attr:`isolation_level` to None. +If you want **autocommit mode**, then set :attr:`isolation_level` to ``None``. Otherwise leave it at its default, which will result in a plain "BEGIN" statement, or set it to one of SQLite's supported isolation levels: "DEFERRED", diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -449,8 +449,8 @@ :meth:`SSLContext.set_default_verify_paths`. The return value is a :term:`named tuple` ``DefaultVerifyPaths``: - * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist, - * :attr:`capath` - resolved path to capath or None if the directory doesn't exist, + * :attr:`cafile` - resolved path to cafile or ``None`` if the file doesn't exist, + * :attr:`capath` - resolved path to capath or ``None`` if the directory doesn't exist, * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile, * :attr:`openssl_cafile` - hard coded path to a cafile, * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath, diff --git a/Doc/library/string.rst b/Doc/library/string.rst --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -448,7 +448,7 @@ In addition to the above presentation types, integers can be formatted with the floating point presentation types listed below (except -``'n'`` and None). When doing so, :func:`float` is used to convert the +``'n'`` and ``None``). When doing so, :func:`float` is used to convert the integer to a floating point number before formatting. The available presentation types for floating point and decimal values are: diff --git a/Doc/library/ttk.rst b/Doc/library/ttk.rst --- a/Doc/library/ttk.rst +++ b/Doc/library/ttk.rst @@ -1380,7 +1380,7 @@ Layouts ^^^^^^^ -A layout can be just None, if it takes no options, or a dict of +A layout can be just ``None``, if it takes no options, or a dict of options specifying how to arrange the element. The layout mechanism uses a simplified version of the pack geometry manager: given an initial cavity, each element is allocated a parcel. Valid diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -529,7 +529,7 @@ :param n: an integer (or ``None``) - Delete all or first/last *n* of turtle's stamps. If *n* is None, delete + Delete all or first/last *n* of turtle's stamps. If *n* is ``None``, delete all stamps, if *n* > 0 delete first *n* stamps, else if *n* < 0 delete last *n* stamps. @@ -1857,10 +1857,10 @@ :param height: if an integer, the height in pixels, if a float, a fraction of the screen; default is 75% of screen :param startx: if positive, starting position in pixels from the left - edge of the screen, if negative from the right edge, if None, + edge of the screen, if negative from the right edge, if ``None``, center window horizontally :param starty: if positive, starting position in pixels from the top - edge of the screen, if negative from the bottom edge, if None, + edge of the screen, if negative from the bottom edge, if ``None``, center window vertically .. doctest:: diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -878,7 +878,7 @@ .. method:: assertIsNone(expr, msg=None) assertIsNotNone(expr, msg=None) - Test that *expr* is (or is not) None. + Test that *expr* is (or is not) ``None``. .. versionadded:: 2.7 @@ -1240,7 +1240,7 @@ methods that delegate to it), :meth:`assertDictEqual` and :meth:`assertMultiLineEqual`. - Setting ``maxDiff`` to None means that there is no maximum length of + Setting ``maxDiff`` to ``None`` means that there is no maximum length of diffs. .. versionadded:: 2.7 diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -639,7 +639,7 @@ .. method:: clear() Resets an element. This function removes all subelements, clears all - attributes, and sets the text and tail attributes to None. + attributes, and sets the text and tail attributes to ``None``. .. method:: get(key, default=None) @@ -855,8 +855,8 @@ Writes the element tree to a file, as XML. *file* is a file name, or a file object opened for writing. *encoding* [1]_ is the output encoding (default is US-ASCII). *xml_declaration* controls if an XML declaration - should be added to the file. Use False for never, True for always, None - for only if not US-ASCII or UTF-8 (default is None). *default_namespace* + should be added to the file. Use False for never, True for always, ``None`` + for only if not US-ASCII or UTF-8 (default is ``None``). *default_namespace* sets the default XML namespace (for "xmlns"). *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). Returns an encoded string. diff --git a/Doc/library/xml.sax.reader.rst b/Doc/library/xml.sax.reader.rst --- a/Doc/library/xml.sax.reader.rst +++ b/Doc/library/xml.sax.reader.rst @@ -306,7 +306,7 @@ Get the byte stream for this input source. The getEncoding method will return the character encoding for this byte stream, - or None if unknown. + or ``None`` if unknown. .. method:: InputSource.setCharacterStream(charfile) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -830,7 +830,7 @@ dictionary containing the class's namespace; :attr:`~class.__bases__` is a tuple (possibly empty or a singleton) containing the base classes, in the order of their occurrence in the base class list; :attr:`__doc__` is the - class's documentation string, or None if undefined. + class's documentation string, or ``None`` if undefined. Class instances .. index:: @@ -1013,7 +1013,7 @@ called at the start of each source code line (this is used by the debugger); :attr:`f_exc_type`, :attr:`f_exc_value`, :attr:`f_exc_traceback` represent the last exception raised in the parent frame provided another exception was ever - raised in the current frame (in all other cases they are None); :attr:`f_lineno` + raised in the current frame (in all other cases they are ``None``); :attr:`f_lineno` is the current line number of the frame --- writing to this from within a trace function jumps to the given line (only for the bottom-most frame). A debugger can implement a Jump command (aka Set Next Statement) by writing to f_lineno. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 09:52:57 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 19 Oct 2016 13:52:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328240=3A_Fix_form?= =?utf-8?q?atting_of_the_warning=2E?= Message-ID: <20161019134939.9581.28279.87DE4B9B@psf.io> https://hg.python.org/cpython/rev/4e4d4e9183f5 changeset: 104560:4e4d4e9183f5 user: Victor Stinner date: Wed Oct 19 15:48:23 2016 +0200 summary: Issue #28240: Fix formatting of the warning. files: Lib/timeit.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -365,8 +365,7 @@ warnings.warn_explicit("The test results are likely unreliable. " "The worst time (%s) was more than four times " "slower than the best time (%s)." - % (precision, - format_time(worst), format_time(best)), + % (format_time(worst), format_time(best)), UserWarning, '', 0) return None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 10:02:28 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 19 Oct 2016 14:02:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogX2NzdjogdXNlIF9QeUxvbmdf?= =?utf-8?q?AsInt=28=29?= Message-ID: <20161019140227.38960.64896.AF75F738@psf.io> https://hg.python.org/cpython/rev/ed470e049058 changeset: 104561:ed470e049058 user: Victor Stinner date: Wed Oct 19 16:00:37 2016 +0200 summary: _csv: use _PyLong_AsInt() files: Modules/_csv.c | 14 ++++---------- 1 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -209,23 +209,17 @@ if (src == NULL) *target = dflt; else { - long value; + int value; if (!PyLong_CheckExact(src)) { PyErr_Format(PyExc_TypeError, "\"%s\" must be an integer", name); return -1; } - value = PyLong_AsLong(src); - if (value == -1 && PyErr_Occurred()) - return -1; -#if SIZEOF_LONG > SIZEOF_INT - if (value > INT_MAX || value < INT_MIN) { - PyErr_Format(PyExc_ValueError, - "integer out of range for \"%s\"", name); + value = _PyLong_AsInt(src); + if (value == -1 && PyErr_Occurred()) { return -1; } -#endif - *target = (int)value; + *target = value; } return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:12:40 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:12:40 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Fixed_markup_errors=2E?= Message-ID: <20161019151239.38734.40315.D05B5E86@psf.io> https://hg.python.org/cpython/rev/9ef78351d2e9 changeset: 104562:9ef78351d2e9 branch: 3.5 parent: 104557:477a82ec81fc user: Serhiy Storchaka date: Wed Oct 19 18:11:24 2016 +0300 summary: Issue #19795: Fixed markup errors. files: Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -548,5 +548,5 @@ * The automatic name remapping in the pickle module for protocol 2 or lower can make Python 3.1 pickles unreadable in Python 3.0. One solution is to use - protocol 3. Another solution is to set the *fix_imports* option to *``False``*. + protocol 3. Another solution is to set the *fix_imports* option to ``False``. See the discussion above for more details. diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -161,7 +161,7 @@ * :ref:`Safe object finalization ` (:pep:`442`). * Leveraging :pep:`442`, in most cases :ref:`module globals are no longer set - to ``None`` during finalization ` (:issue:`18214`). + to None during finalization ` (:issue:`18214`). * :ref:`Configurable memory allocators ` (:pep:`445`). * :ref:`Argument Clinic ` (:pep:`436`). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:12:53 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:12:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2319795=3A_Fixed_markup_errors=2E?= Message-ID: <20161019151239.18103.17232.9D5876F5@psf.io> https://hg.python.org/cpython/rev/6c8a26e60728 changeset: 104563:6c8a26e60728 branch: 3.6 parent: 104558:91992ea3c6b1 parent: 104562:9ef78351d2e9 user: Serhiy Storchaka date: Wed Oct 19 18:12:05 2016 +0300 summary: Issue #19795: Fixed markup errors. files: Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -548,5 +548,5 @@ * The automatic name remapping in the pickle module for protocol 2 or lower can make Python 3.1 pickles unreadable in Python 3.0. One solution is to use - protocol 3. Another solution is to set the *fix_imports* option to *``False``*. + protocol 3. Another solution is to set the *fix_imports* option to ``False``. See the discussion above for more details. diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -161,7 +161,7 @@ * :ref:`Safe object finalization ` (:pep:`442`). * Leveraging :pep:`442`, in most cases :ref:`module globals are no longer set - to ``None`` during finalization ` (:issue:`18214`). + to None during finalization ` (:issue:`18214`). * :ref:`Configurable memory allocators ` (:pep:`445`). * :ref:`Argument Clinic ` (:pep:`436`). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:12:53 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:12:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319795=3A_Fixed_markup_errors=2E?= Message-ID: <20161019151240.27160.97502.FBC9175E@psf.io> https://hg.python.org/cpython/rev/2127ef3b7660 changeset: 104564:2127ef3b7660 parent: 104561:ed470e049058 parent: 104563:6c8a26e60728 user: Serhiy Storchaka date: Wed Oct 19 18:12:24 2016 +0300 summary: Issue #19795: Fixed markup errors. files: Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -548,5 +548,5 @@ * The automatic name remapping in the pickle module for protocol 2 or lower can make Python 3.1 pickles unreadable in Python 3.0. One solution is to use - protocol 3. Another solution is to set the *fix_imports* option to *``False``*. + protocol 3. Another solution is to set the *fix_imports* option to ``False``. See the discussion above for more details. diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -161,7 +161,7 @@ * :ref:`Safe object finalization ` (:pep:`442`). * Leveraging :pep:`442`, in most cases :ref:`module globals are no longer set - to ``None`` during finalization ` (:issue:`18214`). + to None during finalization ` (:issue:`18214`). * :ref:`Configurable memory allocators ` (:pep:`445`). * :ref:`Argument Clinic ` (:pep:`436`). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:37:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:37:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Improved_more_markups_of_True/False=2E?= Message-ID: <20161019153734.32698.6631.483378C4@psf.io> https://hg.python.org/cpython/rev/e4aa34a7ca53 changeset: 104565:e4aa34a7ca53 branch: 3.5 parent: 104562:9ef78351d2e9 user: Serhiy Storchaka date: Wed Oct 19 18:30:05 2016 +0300 summary: Issue #19795: Improved more markups of True/False. files: Doc/c-api/number.rst | 4 ++-- Doc/library/asyncio-eventloop.rst | 4 ++-- Doc/library/asyncio-task.rst | 4 ++-- Doc/library/ctypes.rst | 6 +++--- Doc/library/functools.rst | 2 +- Doc/library/io.rst | 2 +- Doc/library/logging.rst | 2 +- Doc/library/quopri.rst | 2 +- Doc/library/ssl.rst | 2 +- Doc/library/subprocess.rst | 2 +- Doc/library/sysconfig.rst | 2 +- Doc/library/threading.rst | 2 +- Doc/whatsnew/2.7.rst | 10 +++++----- Doc/whatsnew/3.3.rst | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -278,5 +278,5 @@ .. c:function:: int PyIndex_Check(PyObject *o) - Returns True if *o* is an index integer (has the nb_index slot of the - tp_as_number structure filled in). + Returns ``1`` if *o* is an index integer (has the nb_index slot of the + tp_as_number structure filled in), and ``0`` otherwise. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -346,7 +346,7 @@ * *reuse_address* tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified will automatically be set to True on + expire. If not specified will automatically be set to ``True`` on UNIX. * *reuse_port* tells the kernel to allow this endpoint to be bound to the @@ -424,7 +424,7 @@ * *reuse_address* tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified will automatically be set to True on + expire. If not specified will automatically be set to ``True`` on UNIX. * *reuse_port* tells the kernel to allow this endpoint to be bound to the diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -245,7 +245,7 @@ .. method:: done() - Return True if the future is done. + Return ``True`` if the future is done. Done means either that a result / exception are available, or that the future was cancelled. @@ -562,7 +562,7 @@ All futures must share the same event loop. If all the tasks are done successfully, the returned future's result is the list of results (in the order of the original sequence, not necessarily the order of results - arrival). If *return_exceptions* is True, exceptions in the tasks are + arrival). If *return_exceptions* is true, exceptions in the tasks are treated the same as successful results, and gathered in the result list; otherwise, the first raised exception will be immediately propagated to the returned future. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1358,7 +1358,7 @@ ignored. On posix systems, RTLD_NOW is always added, and is not configurable. -The *use_errno* parameter, when set to True, enables a ctypes mechanism that +The *use_errno* parameter, when set to true, enables a ctypes mechanism that allows accessing the system :data:`errno` error number in a safe way. :mod:`ctypes` maintains a thread-local copy of the systems :data:`errno` variable; if you call foreign functions created with ``use_errno=True`` then the @@ -1369,7 +1369,7 @@ copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy to a new value and returns the former value. -The *use_last_error* parameter, when set to True, enables the same mechanism for +The *use_last_error* parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the :func:`GetLastError` and :func:`SetLastError` Windows API functions; :func:`ctypes.get_last_error` and :func:`ctypes.set_last_error` are used to request and change the ctypes private @@ -1579,7 +1579,7 @@ The returned function prototype creates functions that use the standard C calling convention. The function will release the GIL during the call. If - *use_errno* is set to True, the ctypes private copy of the system + *use_errno* is set to true, the ctypes private copy of the system :data:`errno` variable is exchanged with the real :data:`errno` value before and after the call; *use_last_error* does the same for the Windows error code. diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -56,7 +56,7 @@ grow without bound. The LRU feature performs best when *maxsize* is a power-of-two. - If *typed* is set to True, function arguments of different types will be + If *typed* is set to true, function arguments of different types will be cached separately. For example, ``f(3)`` and ``f(3.0)`` will be treated as distinct calls with distinct results. diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -537,7 +537,7 @@ The *name* can be one of two things: * a character string or :class:`bytes` object representing the path to the - file which will be opened. In this case closefd must be True (the default) + file which will be opened. In this case closefd must be ``True`` (the default) otherwise an error will be raised. * an integer representing the number of an existing OS-level file descriptor to which the resulting :class:`FileIO` object will give access. When the diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -318,7 +318,7 @@ looking for handlers in this logger and its parents in the logger hierarchy. Returns ``True`` if a handler was found, else ``False``. The method stops searching up the hierarchy whenever a logger with the 'propagate' attribute set to - False is found - that will be the last logger which is checked for the + false is found - that will be the last logger which is checked for the existence of handlers. .. versionadded:: 3.2 diff --git a/Doc/library/quopri.rst b/Doc/library/quopri.rst --- a/Doc/library/quopri.rst +++ b/Doc/library/quopri.rst @@ -52,7 +52,7 @@ Like :func:`encode`, except that it accepts a source :class:`bytes` and returns the corresponding encoded :class:`bytes`. By default, it sends a - False value to *quotetabs* parameter of the :func:`encode` function. + ``False`` value to *quotetabs* parameter of the :func:`encode` function. diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1387,7 +1387,7 @@ This setting doesn't apply to client sockets. You can also use the :data:`OP_SINGLE_ECDH_USE` option to further improve security. - This method is not available if :data:`HAS_ECDH` is False. + This method is not available if :data:`HAS_ECDH` is ``False``. .. versionadded:: 3.3 diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -64,7 +64,7 @@ is automatically created with ``stdin=PIPE``, and the *stdin* argument may not be used as well. - If *check* is True, and the process exits with a non-zero exit code, a + If *check* is true, and the process exits with a non-zero exit code, a :exc:`CalledProcessError` exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured. diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -152,7 +152,7 @@ If *vars* is provided, it must be a dictionary of variables that will update the dictionary used to expand the paths. - If *expand* is set to False, the paths will not be expanded. + If *expand* is set to false, the paths will not be expanded. If *scheme* is not an existing scheme, :func:`get_paths` will raise a :exc:`KeyError`. diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -615,7 +615,7 @@ .. method:: wait_for(predicate, timeout=None) - Wait until a condition evaluates to True. *predicate* should be a + Wait until a condition evaluates to true. *predicate* should be a callable which result will be interpreted as a boolean value. A *timeout* may be provided giving the maximum time to wait. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -245,8 +245,8 @@ [('first', 1), ('third', 3), ('second', 5)] The :meth:`~collections.OrderedDict.popitem` method has an optional *last* -argument that defaults to True. If *last* is True, the most recently -added key is returned and removed; if it's False, the +argument that defaults to ``True``. If *last* is true, the most recently +added key is returned and removed; if it's false, the oldest key is selected:: >>> od = OrderedDict([(x,0) for x in range(20)]) @@ -1518,7 +1518,7 @@ * The :mod:`SocketServer` module's :class:`~SocketServer.TCPServer` class now supports socket timeouts and disabling the Nagle algorithm. The :attr:`~SocketServer.TCPServer.disable_nagle_algorithm` class attribute - defaults to False; if overridden to be True, + defaults to ``False``; if overridden to be true, new request connections will have the TCP_NODELAY option set to prevent buffering many small sends into a single TCP packet. The :attr:`~SocketServer.BaseServer.timeout` class attribute can hold @@ -1879,7 +1879,7 @@ :meth:`~unittest.TestCase.assertTrue`, and :meth:`~unittest.TestCase.assertFalse` failures now provide more information. If you set the :attr:`~unittest.TestCase.longMessage` attribute of your :class:`~unittest.TestCase` classes to -True, both the standard error message and any additional message you +true, both the standard error message and any additional message you provide will be printed for failures. (Added by Michael Foord; :issue:`5663`.) The :meth:`~unittest.TestCase.assertRaises` method now @@ -1986,7 +1986,7 @@ sequence comparison methods do. :func:`unittest.main` now takes an optional ``exit`` argument. If -False, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing +false, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing :func:`~unittest.main` to be used from the interactive interpreter. (Contributed by J. Pablo Fern?ndez; :issue:`3379`.) 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 @@ -1742,7 +1742,7 @@ ----- * :meth:`~sched.scheduler.run` now accepts a *blocking* parameter which when - set to False makes the method execute the scheduled events due to expire + set to false makes the method execute the scheduled events due to expire soonest (if any) and then return immediately. This is useful in case you want to use the :class:`~sched.scheduler` in non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`.) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:37:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:37:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Improved_more_markups_of_True/False=2E?= Message-ID: <20161019153735.16719.78074.50514536@psf.io> https://hg.python.org/cpython/rev/dd7e48e3e5b0 changeset: 104566:dd7e48e3e5b0 branch: 2.7 parent: 104556:b7df6c09ddf9 user: Serhiy Storchaka date: Wed Oct 19 18:30:16 2016 +0300 summary: Issue #19795: Improved more markups of True/False. files: Doc/c-api/number.rst | 4 ++-- Doc/library/ctypes.rst | 6 +++--- Doc/library/httplib.rst | 2 +- Doc/library/logging.rst | 10 ---------- Doc/library/ssl.rst | 2 +- Doc/library/sysconfig.rst | 2 +- Doc/library/xml.etree.elementtree.rst | 2 +- Doc/whatsnew/2.7.rst | 10 +++++----- 8 files changed, 14 insertions(+), 24 deletions(-) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -316,7 +316,7 @@ .. c:function:: int PyIndex_Check(PyObject *o) - Returns True if *o* is an index integer (has the nb_index slot of the - tp_as_number structure filled in). + Returns ``1`` if *o* is an index integer (has the nb_index slot of the + tp_as_number structure filled in), and ``0`` otherwise. .. versionadded:: 2.5 diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1404,7 +1404,7 @@ ignored. On posix systems, RTLD_NOW is always added, and is not configurable. -The *use_errno* parameter, when set to True, enables a ctypes mechanism that +The *use_errno* parameter, when set to true, enables a ctypes mechanism that allows accessing the system :data:`errno` error number in a safe way. :mod:`ctypes` maintains a thread-local copy of the systems :data:`errno` variable; if you call foreign functions created with ``use_errno=True`` then the @@ -1415,7 +1415,7 @@ copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy to a new value and returns the former value. -The *use_last_error* parameter, when set to True, enables the same mechanism for +The *use_last_error* parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the :func:`GetLastError` and :func:`SetLastError` Windows API functions; :func:`ctypes.get_last_error` and :func:`ctypes.set_last_error` are used to request and change the ctypes private @@ -1631,7 +1631,7 @@ The returned function prototype creates functions that use the standard C calling convention. The function will release the GIL during the call. If - *use_errno* is set to True, the ctypes private copy of the system + *use_errno* is set to true, the ctypes private copy of the system :data:`errno` variable is exchanged with the real :data:`errno` value before and after the call; *use_last_error* does the same for the Windows error code. diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst --- a/Doc/library/httplib.rst +++ b/Doc/library/httplib.rst @@ -49,7 +49,7 @@ server. It should be instantiated passing it a host and optional port number. If no port number is passed, the port is extracted from the host string if it has the form ``host:port``, else the default HTTP port (80) is - used. When True, the optional parameter *strict* (which defaults to a false + used. When true, the optional parameter *strict* (which defaults to a false value) causes ``BadStatusLine`` to be raised if the status line can't be parsed as a valid HTTP/1.0 or 1.1 status line. If the optional *timeout* parameter is given, blocking diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -1026,14 +1026,4 @@ package available from this site is suitable for use with Python 1.5.2, 2.1.x and 2.2.x, which do not include the :mod:`logging` package in the standard library. -<<<<<<< -======= - :lno: The line number in the file where the logging call was made. - :msg: The logging message. - :args: The arguments for the logging message. - :exc_info: An exception tuple, or ``None``. - :func: The name of the function or method which invoked the logging - call. - :sinfo: A stack traceback such as is provided by ->>>>>>> diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1246,7 +1246,7 @@ This setting doesn't apply to client sockets. You can also use the :data:`OP_SINGLE_ECDH_USE` option to further improve security. - This method is not available if :data:`HAS_ECDH` is False. + This method is not available if :data:`HAS_ECDH` is ``False``. .. seealso:: `SSL/TLS & Perfect Forward Secrecy `_ diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -152,7 +152,7 @@ If *vars* is provided, it must be a dictionary of variables that will update the dictionary used to expand the paths. - If *expand* is set to False, the paths will not be expanded. + If *expand* is set to false, the paths will not be expanded. If *scheme* is not an existing scheme, :func:`get_paths` will raise a :exc:`KeyError`. diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -855,7 +855,7 @@ Writes the element tree to a file, as XML. *file* is a file name, or a file object opened for writing. *encoding* [1]_ is the output encoding (default is US-ASCII). *xml_declaration* controls if an XML declaration - should be added to the file. Use False for never, True for always, ``None`` + should be added to the file. Use ``False`` for never, ``True`` for always, ``None`` for only if not US-ASCII or UTF-8 (default is ``None``). *default_namespace* sets the default XML namespace (for "xmlns"). *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). Returns an diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -245,8 +245,8 @@ [('first', 1), ('third', 3), ('second', 5)] The :meth:`~collections.OrderedDict.popitem` method has an optional *last* -argument that defaults to True. If *last* is True, the most recently -added key is returned and removed; if it's False, the +argument that defaults to ``True``. If *last* is true, the most recently +added key is returned and removed; if it's false, the oldest key is selected:: >>> od = OrderedDict([(x,0) for x in range(20)]) @@ -1503,7 +1503,7 @@ * The :mod:`SocketServer` module's :class:`~SocketServer.TCPServer` class now supports socket timeouts and disabling the Nagle algorithm. The :attr:`~SocketServer.TCPServer.disable_nagle_algorithm` class attribute - defaults to False; if overridden to be True, + defaults to ``False``; if overridden to be true, new request connections will have the TCP_NODELAY option set to prevent buffering many small sends into a single TCP packet. The :attr:`~SocketServer.BaseServer.timeout` class attribute can hold @@ -1855,7 +1855,7 @@ :meth:`~unittest.TestCase.assertTrue`, and :meth:`~unittest.TestCase.assertFalse` failures now provide more information. If you set the :attr:`~unittest.TestCase.longMessage` attribute of your :class:`~unittest.TestCase` classes to -True, both the standard error message and any additional message you +true, both the standard error message and any additional message you provide will be printed for failures. (Added by Michael Foord; :issue:`5663`.) The :meth:`~unittest.TestCase.assertRaises` method now @@ -1962,7 +1962,7 @@ sequence comparison methods do. :func:`unittest.main` now takes an optional ``exit`` argument. If -False, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing +false, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing :func:`~unittest.main` to be used from the interactive interpreter. (Contributed by J. Pablo Fern?ndez; :issue:`3379`.) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:37:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:37:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319795=3A_Improved_more_markups_of_True/False=2E?= Message-ID: <20161019153735.32813.65156.8F069768@psf.io> https://hg.python.org/cpython/rev/9fc0f20ea7de changeset: 104568:9fc0f20ea7de parent: 104564:2127ef3b7660 parent: 104567:7b143d6834cf user: Serhiy Storchaka date: Wed Oct 19 18:37:07 2016 +0300 summary: Issue #19795: Improved more markups of True/False. files: Doc/c-api/number.rst | 4 ++-- Doc/library/asyncio-eventloop.rst | 4 ++-- Doc/library/asyncio-task.rst | 4 ++-- Doc/library/ctypes.rst | 6 +++--- Doc/library/functools.rst | 2 +- Doc/library/io.rst | 2 +- Doc/library/logging.rst | 2 +- Doc/library/quopri.rst | 2 +- Doc/library/readline.rst | 2 +- Doc/library/ssl.rst | 2 +- Doc/library/subprocess.rst | 8 ++++---- Doc/library/sysconfig.rst | 2 +- Doc/library/threading.rst | 2 +- Doc/library/zipfile.rst | 2 +- Doc/whatsnew/2.7.rst | 10 +++++----- Doc/whatsnew/3.3.rst | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -278,5 +278,5 @@ .. c:function:: int PyIndex_Check(PyObject *o) - Returns True if *o* is an index integer (has the nb_index slot of the - tp_as_number structure filled in). + Returns ``1`` if *o* is an index integer (has the nb_index slot of the + tp_as_number structure filled in), and ``0`` otherwise. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -347,7 +347,7 @@ * *reuse_address* tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified will automatically be set to True on + expire. If not specified will automatically be set to ``True`` on UNIX. * *reuse_port* tells the kernel to allow this endpoint to be bound to the @@ -425,7 +425,7 @@ * *reuse_address* tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified will automatically be set to True on + expire. If not specified will automatically be set to ``True`` on UNIX. * *reuse_port* tells the kernel to allow this endpoint to be bound to the diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -245,7 +245,7 @@ .. method:: done() - Return True if the future is done. + Return ``True`` if the future is done. Done means either that a result / exception are available, or that the future was cancelled. @@ -562,7 +562,7 @@ All futures must share the same event loop. If all the tasks are done successfully, the returned future's result is the list of results (in the order of the original sequence, not necessarily the order of results - arrival). If *return_exceptions* is True, exceptions in the tasks are + arrival). If *return_exceptions* is true, exceptions in the tasks are treated the same as successful results, and gathered in the result list; otherwise, the first raised exception will be immediately propagated to the returned future. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1365,7 +1365,7 @@ ignored. On posix systems, RTLD_NOW is always added, and is not configurable. -The *use_errno* parameter, when set to True, enables a ctypes mechanism that +The *use_errno* parameter, when set to true, enables a ctypes mechanism that allows accessing the system :data:`errno` error number in a safe way. :mod:`ctypes` maintains a thread-local copy of the systems :data:`errno` variable; if you call foreign functions created with ``use_errno=True`` then the @@ -1376,7 +1376,7 @@ copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy to a new value and returns the former value. -The *use_last_error* parameter, when set to True, enables the same mechanism for +The *use_last_error* parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the :func:`GetLastError` and :func:`SetLastError` Windows API functions; :func:`ctypes.get_last_error` and :func:`ctypes.set_last_error` are used to request and change the ctypes private @@ -1586,7 +1586,7 @@ The returned function prototype creates functions that use the standard C calling convention. The function will release the GIL during the call. If - *use_errno* is set to True, the ctypes private copy of the system + *use_errno* is set to true, the ctypes private copy of the system :data:`errno` variable is exchanged with the real :data:`errno` value before and after the call; *use_last_error* does the same for the Windows error code. diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -56,7 +56,7 @@ grow without bound. The LRU feature performs best when *maxsize* is a power-of-two. - If *typed* is set to True, function arguments of different types will be + If *typed* is set to true, function arguments of different types will be cached separately. For example, ``f(3)`` and ``f(3.0)`` will be treated as distinct calls with distinct results. diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -537,7 +537,7 @@ The *name* can be one of two things: * a character string or :class:`bytes` object representing the path to the - file which will be opened. In this case closefd must be True (the default) + file which will be opened. In this case closefd must be ``True`` (the default) otherwise an error will be raised. * an integer representing the number of an existing OS-level file descriptor to which the resulting :class:`FileIO` object will give access. When the diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -318,7 +318,7 @@ looking for handlers in this logger and its parents in the logger hierarchy. Returns ``True`` if a handler was found, else ``False``. The method stops searching up the hierarchy whenever a logger with the 'propagate' attribute set to - False is found - that will be the last logger which is checked for the + false is found - that will be the last logger which is checked for the existence of handlers. .. versionadded:: 3.2 diff --git a/Doc/library/quopri.rst b/Doc/library/quopri.rst --- a/Doc/library/quopri.rst +++ b/Doc/library/quopri.rst @@ -52,7 +52,7 @@ Like :func:`encode`, except that it accepts a source :class:`bytes` and returns the corresponding encoded :class:`bytes`. By default, it sends a - False value to *quotetabs* parameter of the :func:`encode` function. + ``False`` value to *quotetabs* parameter of the :func:`encode` function. diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -171,7 +171,7 @@ Enable or disable automatic calls to :c:func:`add_history` when reading input via readline. The *enabled* argument should be a Boolean value - that when true, enables auto history, and that when False, disables + that when true, enables auto history, and that when false, disables auto history. .. versionadded:: 3.6 diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1536,7 +1536,7 @@ This setting doesn't apply to client sockets. You can also use the :data:`OP_SINGLE_ECDH_USE` option to further improve security. - This method is not available if :data:`HAS_ECDH` is False. + This method is not available if :data:`HAS_ECDH` is ``False``. .. versionadded:: 3.3 diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -61,16 +61,16 @@ The *input* argument is passed to :meth:`Popen.communicate` and thus to the subprocess's stdin. If used it must be a byte sequence, or a string if - *encoding* or *errors* is specified or *universal_newlines* is True. When + *encoding* or *errors* is specified or *universal_newlines* is true. When used, the internal :class:`Popen` object is automatically created with ``stdin=PIPE``, and the *stdin* argument may not be used as well. - If *check* is True, and the process exits with a non-zero exit code, a + If *check* is true, and the process exits with a non-zero exit code, a :exc:`CalledProcessError` exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured. - If *encoding* or *errors* are specified, or *universal_newlines* is True, + If *encoding* or *errors* are specified, or *universal_newlines* is true, file objects for stdin, stdout and stderr are opened in text mode using the specified *encoding* and *errors* or the :class:`io.TextIOWrapper` default. Otherwise, file objects are opened in binary mode. @@ -259,7 +259,7 @@ .. index:: single: universal newlines; subprocess module - If *encoding* or *errors* are specified, or *universal_newlines* is True, + If *encoding* or *errors* are specified, or *universal_newlines* is true, the file objects *stdin*, *stdout* and *stderr* will be opened in text mode using the *encoding* and *errors* specified in the call or the defaults for :class:`io.TextIOWrapper`. diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -152,7 +152,7 @@ If *vars* is provided, it must be a dictionary of variables that will update the dictionary used to expand the paths. - If *expand* is set to False, the paths will not be expanded. + If *expand* is set to false, the paths will not be expanded. If *scheme* is not an existing scheme, :func:`get_paths` will raise a :exc:`KeyError`. diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -615,7 +615,7 @@ .. method:: wait_for(predicate, timeout=None) - Wait until a condition evaluates to True. *predicate* should be a + Wait until a condition evaluates to true. *predicate* should be a callable which result will be interpreted as a boolean value. A *timeout* may be provided giving the maximum time to wait. diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -518,7 +518,7 @@ .. method:: ZipInfo.is_dir() - Return True if this archive member is a directory. + Return ``True`` if this archive member is a directory. This uses the entry's name: directories should always end with ``/``. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -245,8 +245,8 @@ [('first', 1), ('third', 3), ('second', 5)] The :meth:`~collections.OrderedDict.popitem` method has an optional *last* -argument that defaults to True. If *last* is True, the most recently -added key is returned and removed; if it's False, the +argument that defaults to ``True``. If *last* is true, the most recently +added key is returned and removed; if it's false, the oldest key is selected:: >>> od = OrderedDict([(x,0) for x in range(20)]) @@ -1518,7 +1518,7 @@ * The :mod:`SocketServer` module's :class:`~SocketServer.TCPServer` class now supports socket timeouts and disabling the Nagle algorithm. The :attr:`~SocketServer.TCPServer.disable_nagle_algorithm` class attribute - defaults to False; if overridden to be True, + defaults to ``False``; if overridden to be true, new request connections will have the TCP_NODELAY option set to prevent buffering many small sends into a single TCP packet. The :attr:`~SocketServer.BaseServer.timeout` class attribute can hold @@ -1879,7 +1879,7 @@ :meth:`~unittest.TestCase.assertTrue`, and :meth:`~unittest.TestCase.assertFalse` failures now provide more information. If you set the :attr:`~unittest.TestCase.longMessage` attribute of your :class:`~unittest.TestCase` classes to -True, both the standard error message and any additional message you +true, both the standard error message and any additional message you provide will be printed for failures. (Added by Michael Foord; :issue:`5663`.) The :meth:`~unittest.TestCase.assertRaises` method now @@ -1986,7 +1986,7 @@ sequence comparison methods do. :func:`unittest.main` now takes an optional ``exit`` argument. If -False, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing +false, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing :func:`~unittest.main` to be used from the interactive interpreter. (Contributed by J. Pablo Fern?ndez; :issue:`3379`.) 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 @@ -1742,7 +1742,7 @@ ----- * :meth:`~sched.scheduler.run` now accepts a *blocking* parameter which when - set to False makes the method execute the scheduled events due to expire + set to false makes the method execute the scheduled events due to expire soonest (if any) and then return immediately. This is useful in case you want to use the :class:`~sched.scheduler` in non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`.) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 11:38:06 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 15:38:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2319795=3A_Improved_more_markups_of_True/False=2E?= Message-ID: <20161019153735.27888.97785.A22BF594@psf.io> https://hg.python.org/cpython/rev/7b143d6834cf changeset: 104567:7b143d6834cf branch: 3.6 parent: 104563:6c8a26e60728 parent: 104565:e4aa34a7ca53 user: Serhiy Storchaka date: Wed Oct 19 18:36:51 2016 +0300 summary: Issue #19795: Improved more markups of True/False. files: Doc/c-api/number.rst | 4 ++-- Doc/library/asyncio-eventloop.rst | 4 ++-- Doc/library/asyncio-task.rst | 4 ++-- Doc/library/ctypes.rst | 6 +++--- Doc/library/functools.rst | 2 +- Doc/library/io.rst | 2 +- Doc/library/logging.rst | 2 +- Doc/library/quopri.rst | 2 +- Doc/library/readline.rst | 2 +- Doc/library/ssl.rst | 2 +- Doc/library/subprocess.rst | 8 ++++---- Doc/library/sysconfig.rst | 2 +- Doc/library/threading.rst | 2 +- Doc/library/zipfile.rst | 2 +- Doc/whatsnew/2.7.rst | 10 +++++----- Doc/whatsnew/3.3.rst | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -278,5 +278,5 @@ .. c:function:: int PyIndex_Check(PyObject *o) - Returns True if *o* is an index integer (has the nb_index slot of the - tp_as_number structure filled in). + Returns ``1`` if *o* is an index integer (has the nb_index slot of the + tp_as_number structure filled in), and ``0`` otherwise. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -347,7 +347,7 @@ * *reuse_address* tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified will automatically be set to True on + expire. If not specified will automatically be set to ``True`` on UNIX. * *reuse_port* tells the kernel to allow this endpoint to be bound to the @@ -425,7 +425,7 @@ * *reuse_address* tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified will automatically be set to True on + expire. If not specified will automatically be set to ``True`` on UNIX. * *reuse_port* tells the kernel to allow this endpoint to be bound to the diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -245,7 +245,7 @@ .. method:: done() - Return True if the future is done. + Return ``True`` if the future is done. Done means either that a result / exception are available, or that the future was cancelled. @@ -562,7 +562,7 @@ All futures must share the same event loop. If all the tasks are done successfully, the returned future's result is the list of results (in the order of the original sequence, not necessarily the order of results - arrival). If *return_exceptions* is True, exceptions in the tasks are + arrival). If *return_exceptions* is true, exceptions in the tasks are treated the same as successful results, and gathered in the result list; otherwise, the first raised exception will be immediately propagated to the returned future. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1365,7 +1365,7 @@ ignored. On posix systems, RTLD_NOW is always added, and is not configurable. -The *use_errno* parameter, when set to True, enables a ctypes mechanism that +The *use_errno* parameter, when set to true, enables a ctypes mechanism that allows accessing the system :data:`errno` error number in a safe way. :mod:`ctypes` maintains a thread-local copy of the systems :data:`errno` variable; if you call foreign functions created with ``use_errno=True`` then the @@ -1376,7 +1376,7 @@ copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy to a new value and returns the former value. -The *use_last_error* parameter, when set to True, enables the same mechanism for +The *use_last_error* parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the :func:`GetLastError` and :func:`SetLastError` Windows API functions; :func:`ctypes.get_last_error` and :func:`ctypes.set_last_error` are used to request and change the ctypes private @@ -1586,7 +1586,7 @@ The returned function prototype creates functions that use the standard C calling convention. The function will release the GIL during the call. If - *use_errno* is set to True, the ctypes private copy of the system + *use_errno* is set to true, the ctypes private copy of the system :data:`errno` variable is exchanged with the real :data:`errno` value before and after the call; *use_last_error* does the same for the Windows error code. diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -56,7 +56,7 @@ grow without bound. The LRU feature performs best when *maxsize* is a power-of-two. - If *typed* is set to True, function arguments of different types will be + If *typed* is set to true, function arguments of different types will be cached separately. For example, ``f(3)`` and ``f(3.0)`` will be treated as distinct calls with distinct results. diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -537,7 +537,7 @@ The *name* can be one of two things: * a character string or :class:`bytes` object representing the path to the - file which will be opened. In this case closefd must be True (the default) + file which will be opened. In this case closefd must be ``True`` (the default) otherwise an error will be raised. * an integer representing the number of an existing OS-level file descriptor to which the resulting :class:`FileIO` object will give access. When the diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -318,7 +318,7 @@ looking for handlers in this logger and its parents in the logger hierarchy. Returns ``True`` if a handler was found, else ``False``. The method stops searching up the hierarchy whenever a logger with the 'propagate' attribute set to - False is found - that will be the last logger which is checked for the + false is found - that will be the last logger which is checked for the existence of handlers. .. versionadded:: 3.2 diff --git a/Doc/library/quopri.rst b/Doc/library/quopri.rst --- a/Doc/library/quopri.rst +++ b/Doc/library/quopri.rst @@ -52,7 +52,7 @@ Like :func:`encode`, except that it accepts a source :class:`bytes` and returns the corresponding encoded :class:`bytes`. By default, it sends a - False value to *quotetabs* parameter of the :func:`encode` function. + ``False`` value to *quotetabs* parameter of the :func:`encode` function. diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -171,7 +171,7 @@ Enable or disable automatic calls to :c:func:`add_history` when reading input via readline. The *enabled* argument should be a Boolean value - that when true, enables auto history, and that when False, disables + that when true, enables auto history, and that when false, disables auto history. .. versionadded:: 3.6 diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1536,7 +1536,7 @@ This setting doesn't apply to client sockets. You can also use the :data:`OP_SINGLE_ECDH_USE` option to further improve security. - This method is not available if :data:`HAS_ECDH` is False. + This method is not available if :data:`HAS_ECDH` is ``False``. .. versionadded:: 3.3 diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -61,16 +61,16 @@ The *input* argument is passed to :meth:`Popen.communicate` and thus to the subprocess's stdin. If used it must be a byte sequence, or a string if - *encoding* or *errors* is specified or *universal_newlines* is True. When + *encoding* or *errors* is specified or *universal_newlines* is true. When used, the internal :class:`Popen` object is automatically created with ``stdin=PIPE``, and the *stdin* argument may not be used as well. - If *check* is True, and the process exits with a non-zero exit code, a + If *check* is true, and the process exits with a non-zero exit code, a :exc:`CalledProcessError` exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured. - If *encoding* or *errors* are specified, or *universal_newlines* is True, + If *encoding* or *errors* are specified, or *universal_newlines* is true, file objects for stdin, stdout and stderr are opened in text mode using the specified *encoding* and *errors* or the :class:`io.TextIOWrapper` default. Otherwise, file objects are opened in binary mode. @@ -259,7 +259,7 @@ .. index:: single: universal newlines; subprocess module - If *encoding* or *errors* are specified, or *universal_newlines* is True, + If *encoding* or *errors* are specified, or *universal_newlines* is true, the file objects *stdin*, *stdout* and *stderr* will be opened in text mode using the *encoding* and *errors* specified in the call or the defaults for :class:`io.TextIOWrapper`. diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -152,7 +152,7 @@ If *vars* is provided, it must be a dictionary of variables that will update the dictionary used to expand the paths. - If *expand* is set to False, the paths will not be expanded. + If *expand* is set to false, the paths will not be expanded. If *scheme* is not an existing scheme, :func:`get_paths` will raise a :exc:`KeyError`. diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -615,7 +615,7 @@ .. method:: wait_for(predicate, timeout=None) - Wait until a condition evaluates to True. *predicate* should be a + Wait until a condition evaluates to true. *predicate* should be a callable which result will be interpreted as a boolean value. A *timeout* may be provided giving the maximum time to wait. diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -518,7 +518,7 @@ .. method:: ZipInfo.is_dir() - Return True if this archive member is a directory. + Return ``True`` if this archive member is a directory. This uses the entry's name: directories should always end with ``/``. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -245,8 +245,8 @@ [('first', 1), ('third', 3), ('second', 5)] The :meth:`~collections.OrderedDict.popitem` method has an optional *last* -argument that defaults to True. If *last* is True, the most recently -added key is returned and removed; if it's False, the +argument that defaults to ``True``. If *last* is true, the most recently +added key is returned and removed; if it's false, the oldest key is selected:: >>> od = OrderedDict([(x,0) for x in range(20)]) @@ -1518,7 +1518,7 @@ * The :mod:`SocketServer` module's :class:`~SocketServer.TCPServer` class now supports socket timeouts and disabling the Nagle algorithm. The :attr:`~SocketServer.TCPServer.disable_nagle_algorithm` class attribute - defaults to False; if overridden to be True, + defaults to ``False``; if overridden to be true, new request connections will have the TCP_NODELAY option set to prevent buffering many small sends into a single TCP packet. The :attr:`~SocketServer.BaseServer.timeout` class attribute can hold @@ -1879,7 +1879,7 @@ :meth:`~unittest.TestCase.assertTrue`, and :meth:`~unittest.TestCase.assertFalse` failures now provide more information. If you set the :attr:`~unittest.TestCase.longMessage` attribute of your :class:`~unittest.TestCase` classes to -True, both the standard error message and any additional message you +true, both the standard error message and any additional message you provide will be printed for failures. (Added by Michael Foord; :issue:`5663`.) The :meth:`~unittest.TestCase.assertRaises` method now @@ -1986,7 +1986,7 @@ sequence comparison methods do. :func:`unittest.main` now takes an optional ``exit`` argument. If -False, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing +false, :func:`~unittest.main` doesn't call :func:`sys.exit`, allowing :func:`~unittest.main` to be used from the interactive interpreter. (Contributed by J. Pablo Fern?ndez; :issue:`3379`.) 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 @@ -1742,7 +1742,7 @@ ----- * :meth:`~sched.scheduler.run` now accepts a *blocking* parameter which when - set to False makes the method execute the scheduled events due to expire + set to false makes the method execute the scheduled events due to expire soonest (if any) and then return immediately. This is useful in case you want to use the :class:`~sched.scheduler` in non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`.) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 12:40:05 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 16:40:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Fixed_formatting_a_table=2E?= Message-ID: <20161019164004.68411.97286.8E427548@psf.io> https://hg.python.org/cpython/rev/c445746d0846 changeset: 104569:c445746d0846 branch: 3.5 parent: 104565:e4aa34a7ca53 user: Serhiy Storchaka date: Wed Oct 19 19:37:20 2016 +0300 summary: Issue #19795: Fixed formatting a table. 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 @@ -754,7 +754,7 @@ | | | (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``. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 12:40:05 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 16:40:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319795=3A_Fixed_formatting_a_table=2E?= Message-ID: <20161019164004.32991.16980.952D9EB6@psf.io> https://hg.python.org/cpython/rev/884c9d9159dc changeset: 104571:884c9d9159dc parent: 104568:9fc0f20ea7de parent: 104570:3b554c9ea1c4 user: Serhiy Storchaka date: Wed Oct 19 19:38:22 2016 +0300 summary: Issue #19795: Fixed formatting a table. 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 @@ -754,7 +754,7 @@ | | | (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``. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 12:40:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 16:40:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2319795=3A_Fixed_formatting_a_table=2E?= Message-ID: <20161019164004.25155.81293.5EAEE8CC@psf.io> https://hg.python.org/cpython/rev/3b554c9ea1c4 changeset: 104570:3b554c9ea1c4 branch: 3.6 parent: 104567:7b143d6834cf parent: 104569:c445746d0846 user: Serhiy Storchaka date: Wed Oct 19 19:37:44 2016 +0300 summary: Issue #19795: Fixed formatting a table. 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 @@ -754,7 +754,7 @@ | | | (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``. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 12:40:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Oct 2016 16:40:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5Nzk1?= =?utf-8?q?=3A_Fixed_formatting_a_table=2E?= Message-ID: <20161019164004.17968.25049.BB90E397@psf.io> https://hg.python.org/cpython/rev/ddf32a646457 changeset: 104572:ddf32a646457 branch: 2.7 parent: 104566:dd7e48e3e5b0 user: Serhiy Storchaka date: Wed Oct 19 19:37:20 2016 +0300 summary: Issue #19795: Fixed formatting a table. 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 @@ -636,7 +636,7 @@ | | | (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``. | +| | format this yourself. | if no exception has occurred, ``None``. | +----------------+-------------------------+-----------------------------------------------+ | filename | ``%(filename)s`` | Filename portion of ``pathname``. | +----------------+-------------------------+-----------------------------------------------+ -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Wed Oct 19 13:22:15 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 19 Oct 2016 18:22:15 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-19 Message-ID: <43cbfb11-99e2-4a4c-9768-351053485c66@irsmsx105.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-19 02:47:51 +0000 commit: 3b22c99535d0 previous commit: 7dd0910e8fbf revision date: 2016-10-16 17:14:23 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.21% 0.05% 5.72% 3.83% :-) pybench 0.23% 0.05% 6.08% 4.23% :-( regex_v8 0.66% -0.00% -2.10% 11.18% :-) nbody 0.07% -0.01% 7.95% 5.30% :-) json_dump_v2 0.31% 0.23% 2.71% 10.06% :-| normal_startup 0.52% -0.14% -0.38% 2.76% :-) ssbench 0.23% 0.78% 2.43% 1.24% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-19/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Wed Oct 19 13:26:06 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 19 Oct 2016 18:26:06 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-19 Message-ID: <0b62a752-b447-4611-aa0a-5386c415f97c@irsmsx105.ger.corp.intel.com> Results for project Python default, build date 2016-10-19 02:01:32 +0000 commit: 554fb699af8c previous commit: 3a58b70345e3 revision date: 2016-10-18 20:04:40 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.18% 1.00% 5.54% 14.04% :-) pybench 0.16% -0.11% 5.24% 4.98% :-( regex_v8 3.67% 0.05% -3.60% 4.02% :-) nbody 0.19% 0.33% 4.26% 3.51% :-( json_dump_v2 0.29% 1.06% -10.46% 14.32% :-| normal_startup 0.73% 0.36% -0.32% 6.30% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-19/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Wed Oct 19 18:46:47 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 19 Oct 2016 22:46:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogQ2xvc2UgIzI4NDc5?= =?utf-8?q?=3A_Fix_reST_syntax_in_windows=2Erst?= Message-ID: <20161019224644.27271.90733.CF87A087@psf.io> https://hg.python.org/cpython/rev/39ac5093bdbb changeset: 104573:39ac5093bdbb branch: 3.6 parent: 104570:3b554c9ea1c4 user: Victor Stinner date: Thu Oct 20 00:45:50 2016 +0200 summary: Close #28479: Fix reST syntax in windows.rst Patch written by Julien Palard. files: Doc/using/windows.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -818,10 +818,10 @@ .. versionchanged:: 3.6 - * Adds ``._pth`` file support and removes ``applocal`` option from - ``pyvenv.cfg``. - * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent - to the executable. + * Adds ``._pth`` file support and removes ``applocal`` option from + ``pyvenv.cfg``. + * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent + to the executable. Additional modules ================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 18:46:47 2016 From: python-checkins at python.org (victor.stinner) Date: Wed, 19 Oct 2016 22:46:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42?= Message-ID: <20161019224644.25529.55295.2EE7838D@psf.io> https://hg.python.org/cpython/rev/1ce50f7027c1 changeset: 104574:1ce50f7027c1 parent: 104571:884c9d9159dc parent: 104573:39ac5093bdbb user: Victor Stinner date: Thu Oct 20 00:46:38 2016 +0200 summary: Merge 3.6 files: Doc/using/windows.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -818,10 +818,10 @@ .. versionchanged:: 3.6 - * Adds ``._pth`` file support and removes ``applocal`` option from - ``pyvenv.cfg``. - * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent - to the executable. + * Adds ``._pth`` file support and removes ``applocal`` option from + ``pyvenv.cfg``. + * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent + to the executable. Additional modules ================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Oct 19 23:57:42 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 03:57:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4NDgw?= =?utf-8?q?=3A_Avoid_label_at_end_of_compound_statement_--without-threads?= Message-ID: <20161020035742.38738.9727.E49FE299@psf.io> https://hg.python.org/cpython/rev/17629dee23ca changeset: 104575:17629dee23ca branch: 2.7 parent: 104572:ddf32a646457 user: Martin Panter date: Thu Oct 20 03:56:48 2016 +0000 summary: Issue #28480: Avoid label at end of compound statement --without-threads files: Misc/NEWS | 3 +++ Modules/_sqlite/connection.c | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,9 @@ Library ------- +- Issue #28480: Fix error building _sqlite3 module when multithreading is + disabled. + - Issue #24452: Make webbrowser support Chrome on Mac OS X. - Issue #26293: Fixed writing ZIP files that starts not from the start of the diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -790,6 +790,7 @@ } error: + ; /* necessary for --without-threads flag */ #ifdef WITH_THREAD PyGILState_Release(threadstate); #endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 01:31:08 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 05:31:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDgw?= =?utf-8?q?=3A_Adjust_or_skip_tests_if_multithreading_is_disabled?= Message-ID: <20161020053108.32920.44357.418AAA76@psf.io> https://hg.python.org/cpython/rev/7cb86d404866 changeset: 104577:7cb86d404866 branch: 3.6 user: Martin Panter date: Thu Oct 20 05:10:44 2016 +0000 summary: Issue #28480: Adjust or skip tests if multithreading is disabled files: Lib/test/test_asyncgen.py | 4 +++- Lib/test/test_logging.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1,4 +1,3 @@ -import asyncio import inspect import sys import types @@ -6,6 +5,9 @@ from unittest import mock +from test.support import import_module +asyncio = import_module("asyncio") + class AwaitException(Exception): pass 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 @@ -4304,7 +4304,7 @@ 'logProcesses', 'currentframe', 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle', 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger', - 'root'} + 'root', 'threading'} support.check__all__(self, logging, blacklist=blacklist) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 01:31:10 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 05:31:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328480=3A_Merge_multithreading_fixes_from_3=2E6?= Message-ID: <20161020053108.18138.93870.ADA50631@psf.io> https://hg.python.org/cpython/rev/948cf38793ce changeset: 104578:948cf38793ce parent: 104574:1ce50f7027c1 parent: 104577:7cb86d404866 user: Martin Panter date: Thu Oct 20 05:25:14 2016 +0000 summary: Issue #28480: Merge multithreading fixes from 3.6 files: Lib/test/test_asyncgen.py | 4 +++- Lib/test/test_logging.py | 2 +- Misc/NEWS | 3 +++ Modules/socketmodule.c | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1,4 +1,3 @@ -import asyncio import inspect import sys import types @@ -6,6 +5,9 @@ from unittest import mock +from test.support import import_module +asyncio = import_module("asyncio") + class AwaitException(Exception): pass 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 @@ -4304,7 +4304,7 @@ 'logProcesses', 'currentframe', 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle', 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger', - 'root'} + 'root', 'threading'} support.check__all__(self, logging, blacklist=blacklist) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ Library ------- +- Issue #28480: Fix error building socket module when multithreading is + disabled. + - Issue #28240: timeit: remove ``-c/--clock`` and ``-t/--time`` command line options which were deprecated since Python 3.3. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -664,6 +664,7 @@ result = 0; done: + ; /* necessary for --without-threads flag */ Py_END_ALLOW_THREADS if (result) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 01:31:10 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 05:31:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDgw?= =?utf-8?q?=3A_Avoid_label_at_end_of_compound_statement_--without-threads?= Message-ID: <20161020053107.11987.94555.D6CD765E@psf.io> https://hg.python.org/cpython/rev/9316b4ebf3fa changeset: 104576:9316b4ebf3fa branch: 3.6 parent: 104573:39ac5093bdbb user: Martin Panter date: Thu Oct 20 00:48:23 2016 +0000 summary: Issue #28480: Avoid label at end of compound statement --without-threads Based on patch by Masayuki Yamamoto. files: Misc/NEWS | 3 +++ Modules/socketmodule.c | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,9 @@ Library ------- +- Issue #28480: Fix error building socket module when multithreading is + disabled. + - Issue #24452: Make webbrowser support Chrome on Mac OS X. - Issue #20766: Fix references leaked by pdb in the handling of SIGINT diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -664,6 +664,7 @@ result = 0; done: + ; /* necessary for --without-threads flag */ Py_END_ALLOW_THREADS if (result) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 04:36:59 2016 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 20 Oct 2016 08:36:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_cum=5Fweights_example_?= =?utf-8?q?=28simulation_of_a_cumulative_binomial_distribution=29=2E?= Message-ID: <20161020083658.18383.30880.E3CC6640@psf.io> https://hg.python.org/cpython/rev/73ed94ebdbbc changeset: 104579:73ed94ebdbbc user: Raymond Hettinger date: Thu Oct 20 01:36:52 2016 -0700 summary: Add cum_weights example (simulation of a cumulative binomial distribution). files: Doc/library/random.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -351,6 +351,13 @@ >>> choices(['red', 'black', 'green'], [18, 18, 2], k=6) ['red', 'green', 'black', 'black', 'red', 'black'] + # Probability of getting 5 or more heads from 7 spins of a biased coin + # that settles on heads 60% of the time. + >>> n = 10000 + >>> cw = [0.60, 1.00] + >>> sum(choices('HT', cum_weights=cw, k=7).count('H') >= 5 for i in range(n)) / n + 0.4169 + Example of `statistical bootstrapping `_ using resampling with replacement to estimate a confidence interval for the mean of a small -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 06:19:57 2016 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Oct 2016 10:19:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321955=3A_Please_d?= =?utf-8?q?on=27t_try_to_optimize_int+int?= Message-ID: <20161020101957.33288.70758.43A4AA68@psf.io> https://hg.python.org/cpython/rev/61fcb12a9873 changeset: 104580:61fcb12a9873 user: Victor Stinner date: Thu Oct 20 12:18:10 2016 +0200 summary: Issue #21955: Please don't try to optimize int+int files: Python/ceval.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1424,6 +1424,12 @@ PyObject *right = POP(); PyObject *left = TOP(); PyObject *sum; + /* NOTE(haypo): Please don't try to micro-optimize int+int on + CPython using bytecode, it is simply worthless. + See http://bugs.python.org/issue21955 and + http://bugs.python.org/issue10044 for the discussion. In short, + no patch shown any impact on a realistic benchmark, only a minor + speedup on microbenchmarks. */ if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) { sum = unicode_concatenate(left, right, f, next_instr); -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Thu Oct 20 09:25:36 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 20 Oct 2016 14:25:36 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python Default 2016-10-20 Message-ID: Results for project Python default, build date 2016-10-20 02:01:47 +0000 commit: 1ce50f7027c1 previous commit: 554fb699af8c revision date: 2016-10-19 22:46:38 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.14% 0.96% 6.44% 14.46% :-) pybench 0.09% 0.02% 5.26% 4.56% :-( regex_v8 3.69% 0.22% -3.38% 4.56% :-) nbody 0.15% -0.08% 4.19% 3.08% :-( json_dump_v2 0.32% -0.27% -10.76% 17.03% :-| normal_startup 0.45% -0.21% 0.26% 6.63% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-default-2016-10-20/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Thu Oct 20 09:24:41 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 20 Oct 2016 14:24:41 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-20 Message-ID: <64e170d0-0df9-468d-babc-f1d5461c9b7c@irsmsx101.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-20 02:48:09 +0000 commit: ddf32a646457 previous commit: 3b22c99535d0 revision date: 2016-10-19 16:37:20 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.15% -0.65% 5.12% 6.29% :-) pybench 0.19% -0.02% 6.06% 3.71% :-( regex_v8 0.67% 0.00% -2.09% 10.65% :-) nbody 0.07% 0.01% 7.96% 2.95% :-) json_dump_v2 0.32% -0.17% 2.55% 10.65% :-| normal_startup 0.59% 0.05% -0.32% 2.62% :-) ssbench 0.21% -0.25% 2.17% 1.21% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-20/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Thu Oct 20 13:12:00 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 17:12:00 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_+_document_CO=5FASYNC=5FGENERATOR=3B_issue_=232601?= =?utf-8?q?0?= Message-ID: <20161020171154.27413.2643.3A9B436E@psf.io> https://hg.python.org/cpython/rev/5023c182a8a4 changeset: 104582:5023c182a8a4 branch: 3.6 parent: 104577:7cb86d404866 parent: 104581:681924a9eefd user: Yury Selivanov date: Thu Oct 20 13:11:34 2016 -0400 summary: Merge 3.5 + document CO_ASYNC_GENERATOR; issue #26010 files: Doc/library/inspect.rst | 69 +++++++++++++++++++++++++++- 1 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -152,9 +152,9 @@ | | co_firstlineno | number of first line in | | | | Python source code | +-----------+-----------------+---------------------------+ -| | co_flags | bitmap: 1=optimized ``|`` | -| | | 2=newlocals ``|`` 4=\*arg | -| | | ``|`` 8=\*\*arg | +| | co_flags | bitmap of ``CO_*`` flags, | +| | | read more :ref:`here | +| | | `| +-----------+-----------------+---------------------------+ | | co_lnotab | encoded mapping of line | | | | numbers to bytecode | @@ -1221,6 +1221,69 @@ .. versionadded:: 3.5 +.. _inspect-module-co-flags: + +Code Objects Bit Flags +---------------------- + +Python code objects have a ``co_flags`` attribute, which is a bitmap of +the following flags: + +.. data:: CO_NEWLOCALS + + If set, a new dict will be created for the frame's ``f_locals`` when + the code object is executed. + +.. data:: CO_VARARGS + + The code object has a variable positional parameter (``*args``-like). + +.. data:: CO_VARKEYWORDS + + The code object has a variable keyword parameter (``**kwargs``-like). + +.. data:: CO_GENERATOR + + The flag is set when the code object is a generator function, i.e. + a generator object is returned when the code object is executed. + +.. data:: CO_NOFREE + + The flag is set if there are no free or cell variables. + +.. data:: CO_COROUTINE + + The flag is set when the code object is a coroutine function, i.e. + a coroutine object is returned when the code object is executed. See + :pep:`492` for more details. + + .. versionadded:: 3.5 + +.. data:: CO_ITERABLE_COROUTINE + + Used to turn generators into generator-based coroutines. Generator + objects with this flag can be used in ``await`` expression, and can + ``yield from`` coroutine objects. See :pep:`492` for more details. + + .. versionadded:: 3.5 + +.. data:: CO_ASYNC_GENERATOR + + The flag is set when the code object is a asynchronous generator + function, i.e. an asynchronous generator object is returned when the + code object is executed. See :pep:`525` for more details. + + .. versionadded:: 3.6 + +.. note:: + The flags are specific to CPython, and may not be defined in other + Python implementations. Furthermore, the flags are an implementation + detail, and can be removed or deprecated in future Python releases. + It's recommended to use public APIs from the :mod:`inspect` module + for any introspection needs. + + + .. _inspect-module-cli: Command Line Interface -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 13:12:00 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 17:12:00 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2MDEw?= =?utf-8?q?=3A_Document_CO=5F*_constants?= Message-ID: <20161020171154.12110.72649.483CDA49@psf.io> https://hg.python.org/cpython/rev/681924a9eefd changeset: 104581:681924a9eefd branch: 3.5 parent: 104569:c445746d0846 user: Yury Selivanov date: Thu Oct 20 13:06:30 2016 -0400 summary: Issue #26010: Document CO_* constants files: Doc/library/inspect.rst | 61 +++++++++++++++++++++++++++- 1 files changed, 58 insertions(+), 3 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -152,9 +152,9 @@ | | co_firstlineno | number of first line in | | | | Python source code | +-----------+-----------------+---------------------------+ -| | co_flags | bitmap: 1=optimized ``|`` | -| | | 2=newlocals ``|`` 4=\*arg | -| | | ``|`` 8=\*\*arg | +| | co_flags | bitmap of ``CO_*`` flags, | +| | | read more :ref:`here | +| | | `| +-----------+-----------------+---------------------------+ | | co_lnotab | encoded mapping of line | | | | numbers to bytecode | @@ -1232,6 +1232,61 @@ .. versionadded:: 3.5 +.. _inspect-module-co-flags: + +Code Objects Bit Flags +---------------------- + +Python code objects have a ``co_flags`` attribute, which is a bitmap of +the following flags: + +.. data:: CO_NEWLOCALS + + If set, a new dict will be created for the frame's ``f_locals`` when + the code object is executed. + +.. data:: CO_VARARGS + + The code object has a variable positional parameter (``*args``-like). + +.. data:: CO_VARKEYWORDS + + The code object has a variable keyword parameter (``**kwargs``-like). + +.. data:: CO_GENERATOR + + The flag is set when the code object is a generator function, i.e. + a generator object is returned when the code object is executed. + +.. data:: CO_NOFREE + + The flag is set if there are no free or cell variables. + +.. data:: CO_COROUTINE + + The flag is set when the code object is a coroutine function, i.e. + a coroutine object is returned when the code object is executed. See + :pep:`492` for more details. + + .. versionadded:: 3.5 + +.. data:: CO_ITERABLE_COROUTINE + + Used to turn generators into generator-based coroutines. Generator + objects with this flag can be used in ``await`` expression, and can + ``yield from`` coroutine objects. See :pep:`492` for more details. + + .. versionadded:: 3.5 + +.. note:: + The flags are specific to CPython, and may not be defined in other + Python implementations. Furthermore, the flags are an implementation + detail, and can be removed or deprecated in future Python releases. + It's recommended to use public APIs from the :mod:`inspect` module + for any introspection needs. + + + .. _inspect-module-cli: Command Line Interface -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 13:12:00 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 17:12:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjYwMTAp?= Message-ID: <20161020171154.27231.12205.1EBD8782@psf.io> https://hg.python.org/cpython/rev/3c4833d2fdbe changeset: 104583:3c4833d2fdbe parent: 104580:61fcb12a9873 parent: 104582:5023c182a8a4 user: Yury Selivanov date: Thu Oct 20 13:11:48 2016 -0400 summary: Merge 3.6 (issue #26010) files: Doc/library/inspect.rst | 69 +++++++++++++++++++++++++++- 1 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -152,9 +152,9 @@ | | co_firstlineno | number of first line in | | | | Python source code | +-----------+-----------------+---------------------------+ -| | co_flags | bitmap: 1=optimized ``|`` | -| | | 2=newlocals ``|`` 4=\*arg | -| | | ``|`` 8=\*\*arg | +| | co_flags | bitmap of ``CO_*`` flags, | +| | | read more :ref:`here | +| | | `| +-----------+-----------------+---------------------------+ | | co_lnotab | encoded mapping of line | | | | numbers to bytecode | @@ -1221,6 +1221,69 @@ .. versionadded:: 3.5 +.. _inspect-module-co-flags: + +Code Objects Bit Flags +---------------------- + +Python code objects have a ``co_flags`` attribute, which is a bitmap of +the following flags: + +.. data:: CO_NEWLOCALS + + If set, a new dict will be created for the frame's ``f_locals`` when + the code object is executed. + +.. data:: CO_VARARGS + + The code object has a variable positional parameter (``*args``-like). + +.. data:: CO_VARKEYWORDS + + The code object has a variable keyword parameter (``**kwargs``-like). + +.. data:: CO_GENERATOR + + The flag is set when the code object is a generator function, i.e. + a generator object is returned when the code object is executed. + +.. data:: CO_NOFREE + + The flag is set if there are no free or cell variables. + +.. data:: CO_COROUTINE + + The flag is set when the code object is a coroutine function, i.e. + a coroutine object is returned when the code object is executed. See + :pep:`492` for more details. + + .. versionadded:: 3.5 + +.. data:: CO_ITERABLE_COROUTINE + + Used to turn generators into generator-based coroutines. Generator + objects with this flag can be used in ``await`` expression, and can + ``yield from`` coroutine objects. See :pep:`492` for more details. + + .. versionadded:: 3.5 + +.. data:: CO_ASYNC_GENERATOR + + The flag is set when the code object is a asynchronous generator + function, i.e. an asynchronous generator object is returned when the + code object is executed. See :pep:`525` for more details. + + .. versionadded:: 3.6 + +.. note:: + The flags are specific to CPython, and may not be defined in other + Python implementations. Furthermore, the flags are an implementation + detail, and can be removed or deprecated in future Python releases. + It's recommended to use public APIs from the :mod:`inspect` module + for any introspection needs. + + + .. _inspect-module-cli: Command Line Interface -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 15:42:57 2016 From: python-checkins at python.org (ned.deily) Date: Thu, 20 Oct 2016 19:42:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2324381=3A_merge_from_3=2E6?= Message-ID: <20161020194236.27387.67720.306EB76F@psf.io> https://hg.python.org/cpython/rev/59838bede1de changeset: 104586:59838bede1de parent: 104583:3c4833d2fdbe parent: 104585:c60d41590054 user: Ned Deily date: Thu Oct 20 15:40:56 2016 -0400 summary: Issue #24381: merge from 3.6 files: Modules/_ctypes/libffi_osx/ffi.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/libffi_osx/ffi.c b/Modules/_ctypes/libffi_osx/ffi.c --- a/Modules/_ctypes/libffi_osx/ffi.c +++ b/Modules/_ctypes/libffi_osx/ffi.c @@ -102,7 +102,7 @@ /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ -#if defined(X86_DARWIN) +#if defined(X86_DARWIN) && !defined __x86_64__ static inline bool struct_on_stack( @@ -125,7 +125,7 @@ } } -#endif // defined(X86_DARWIN) +#endif // defined(X86_DARWIN) && !defined __x86_64__ // Arguments' ffi_type->alignment must be nonzero. ffi_status -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 15:42:57 2016 From: python-checkins at python.org (ned.deily) Date: Thu, 20 Oct 2016 19:42:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2324381=3A_merge_from_3=2E5?= Message-ID: <20161020194236.12073.37871.2100AF2B@psf.io> https://hg.python.org/cpython/rev/c60d41590054 changeset: 104585:c60d41590054 branch: 3.6 parent: 104582:5023c182a8a4 parent: 104584:2b089035a453 user: Ned Deily date: Thu Oct 20 15:40:22 2016 -0400 summary: Issue #24381: merge from 3.5 files: Modules/_ctypes/libffi_osx/ffi.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/libffi_osx/ffi.c b/Modules/_ctypes/libffi_osx/ffi.c --- a/Modules/_ctypes/libffi_osx/ffi.c +++ b/Modules/_ctypes/libffi_osx/ffi.c @@ -102,7 +102,7 @@ /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ -#if defined(X86_DARWIN) +#if defined(X86_DARWIN) && !defined __x86_64__ static inline bool struct_on_stack( @@ -125,7 +125,7 @@ } } -#endif // defined(X86_DARWIN) +#endif // defined(X86_DARWIN) && !defined __x86_64__ // Arguments' ffi_type->alignment must be nonzero. ffi_status -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 15:42:57 2016 From: python-checkins at python.org (ned.deily) Date: Thu, 20 Oct 2016 19:42:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI0Mzgx?= =?utf-8?q?=3A_Avoid_unused_function_warning_when_building_bundled_macOS_l?= =?utf-8?q?ibffi=2E?= Message-ID: <20161020194236.18327.83276.8AC87156@psf.io> https://hg.python.org/cpython/rev/cca20d28f348 changeset: 104587:cca20d28f348 branch: 2.7 parent: 104575:17629dee23ca user: Ned Deily date: Thu Oct 20 15:41:11 2016 -0400 summary: Issue #24381: Avoid unused function warning when building bundled macOS libffi. Patch by Vajrasky Kok. files: Modules/_ctypes/libffi_osx/ffi.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/libffi_osx/ffi.c b/Modules/_ctypes/libffi_osx/ffi.c --- a/Modules/_ctypes/libffi_osx/ffi.c +++ b/Modules/_ctypes/libffi_osx/ffi.c @@ -101,7 +101,7 @@ /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ -#if defined(X86_DARWIN) +#if defined(X86_DARWIN) && !defined __x86_64__ static inline bool struct_on_stack( @@ -124,7 +124,7 @@ } } -#endif // defined(X86_DARWIN) +#endif // defined(X86_DARWIN) && !defined __x86_64__ // Arguments' ffi_type->alignment must be nonzero. ffi_status -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 15:42:57 2016 From: python-checkins at python.org (ned.deily) Date: Thu, 20 Oct 2016 19:42:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI0Mzgx?= =?utf-8?q?=3A_Avoid_unused_function_warning_when_building_bundled_macOS_l?= =?utf-8?q?ibffi=2E?= Message-ID: <20161020194236.9460.74554.764EF078@psf.io> https://hg.python.org/cpython/rev/2b089035a453 changeset: 104584:2b089035a453 branch: 3.5 parent: 104581:681924a9eefd user: Ned Deily date: Thu Oct 20 15:38:27 2016 -0400 summary: Issue #24381: Avoid unused function warning when building bundled macOS libffi. Patch by Vajrasky Kok. files: Modules/_ctypes/libffi_osx/ffi.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/libffi_osx/ffi.c b/Modules/_ctypes/libffi_osx/ffi.c --- a/Modules/_ctypes/libffi_osx/ffi.c +++ b/Modules/_ctypes/libffi_osx/ffi.c @@ -102,7 +102,7 @@ /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ -#if defined(X86_DARWIN) +#if defined(X86_DARWIN) && !defined __x86_64__ static inline bool struct_on_stack( @@ -125,7 +125,7 @@ } } -#endif // defined(X86_DARWIN) +#endif // defined(X86_DARWIN) && !defined __x86_64__ // Arguments' ffi_type->alignment must be nonzero. ffi_status -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 15:55:10 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 19:55:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDky?= =?utf-8?q?=3A_Fix_how_StopIteration_is_raised_in_=5Fasyncio=2EFuture?= Message-ID: <20161020195455.18327.21394.4949BD73@psf.io> https://hg.python.org/cpython/rev/cfe2109ce2c0 changeset: 104588:cfe2109ce2c0 branch: 3.6 parent: 104585:c60d41590054 user: Yury Selivanov date: Thu Oct 20 15:54:20 2016 -0400 summary: Issue #28492: Fix how StopIteration is raised in _asyncio.Future files: Lib/test/test_asyncio/test_futures.py | 13 +++++++++ Misc/NEWS | 2 + Modules/_asynciomodule.c | 21 +++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -464,6 +464,19 @@ futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) + def test_future_stop_iteration_args(self): + fut = asyncio.Future(loop=self.loop) + fut.set_result((1, 2)) + fi = fut.__iter__() + result = None + try: + fi.send(None) + except StopIteration as ex: + result = ex.args[0] + else: + self.fail('StopIteration was expected') + self.assertEqual(result, (1, 2)) + class FutureDoneCallbackTests(test_utils.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,8 @@ - Issue #20766: Fix references leaked by pdb in the handling of SIGINT handlers. +- Issue #28492: Fix how StopIteration exception is raised in _asyncio.Future. + Build ----- diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -787,9 +787,26 @@ res = FutureObj_result(fut, NULL); if (res != NULL) { - // normal result - PyErr_SetObject(PyExc_StopIteration, res); + /* The result of the Future is not an exception. + + We cunstruct an exception instance manually with + PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject + (similarly to what genobject.c does). + + This is to handle a situation when "res" is a tuple, in which + case PyErr_SetObject would set the value of StopIteration to + the first element of the tuple. + + (See PyErr_SetObject/_PyErr_CreateException code for details.) + */ + PyObject *e = PyObject_CallFunctionObjArgs( + PyExc_StopIteration, res, NULL); Py_DECREF(res); + if (e == NULL) { + return NULL; + } + PyErr_SetObject(PyExc_StopIteration, e); + Py_DECREF(e); } it->future = NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 15:55:10 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 19:55:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg0OTIp?= Message-ID: <20161020195455.25092.72501.0C209062@psf.io> https://hg.python.org/cpython/rev/79b9257f3386 changeset: 104589:79b9257f3386 parent: 104586:59838bede1de parent: 104588:cfe2109ce2c0 user: Yury Selivanov date: Thu Oct 20 15:54:51 2016 -0400 summary: Merge 3.6 (issue #28492) files: Lib/test/test_asyncio/test_futures.py | 13 +++++++++ Modules/_asynciomodule.c | 21 +++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -464,6 +464,19 @@ futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) + def test_future_stop_iteration_args(self): + fut = asyncio.Future(loop=self.loop) + fut.set_result((1, 2)) + fi = fut.__iter__() + result = None + try: + fi.send(None) + except StopIteration as ex: + result = ex.args[0] + else: + self.fail('StopIteration was expected') + self.assertEqual(result, (1, 2)) + class FutureDoneCallbackTests(test_utils.TestCase): diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -787,9 +787,26 @@ res = FutureObj_result(fut, NULL); if (res != NULL) { - // normal result - PyErr_SetObject(PyExc_StopIteration, res); + /* The result of the Future is not an exception. + + We cunstruct an exception instance manually with + PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject + (similarly to what genobject.c does). + + This is to handle a situation when "res" is a tuple, in which + case PyErr_SetObject would set the value of StopIteration to + the first element of the tuple. + + (See PyErr_SetObject/_PyErr_CreateException code for details.) + */ + PyObject *e = PyObject_CallFunctionObjArgs( + PyExc_StopIteration, res, NULL); Py_DECREF(res); + if (e == NULL) { + return NULL; + } + PyErr_SetObject(PyExc_StopIteration, e); + Py_DECREF(e); } it->future = NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 16:31:21 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 20:31:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI2MDEw?= =?utf-8?q?=3A_fix_typos=3B_rewording?= Message-ID: <20161020203120.68540.48694.775DABC4@psf.io> https://hg.python.org/cpython/rev/761414979de5 changeset: 104590:761414979de5 branch: 3.6 parent: 104588:cfe2109ce2c0 user: Yury Selivanov date: Thu Oct 20 16:30:51 2016 -0400 summary: Issue #26010: fix typos; rewording files: Doc/library/inspect.rst | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1253,25 +1253,26 @@ .. data:: CO_COROUTINE - The flag is set when the code object is a coroutine function, i.e. - a coroutine object is returned when the code object is executed. See - :pep:`492` for more details. + The flag is set when the code object is a coroutine function. + When the code object is executed it returns a coroutine object. + See :pep:`492` for more details. .. versionadded:: 3.5 .. data:: CO_ITERABLE_COROUTINE - Used to turn generators into generator-based coroutines. Generator - objects with this flag can be used in ``await`` expression, and can - ``yield from`` coroutine objects. See :pep:`492` for more details. + The flag is used to transform generators into generator-based + coroutines. Generator objects with this flag can be used in + ``await`` expression, and can ``yield from`` coroutine objects. + See :pep:`492` for more details. .. versionadded:: 3.5 .. data:: CO_ASYNC_GENERATOR - The flag is set when the code object is a asynchronous generator - function, i.e. an asynchronous generator object is returned when the - code object is executed. See :pep:`525` for more details. + The flag is set when the code object is an asynchronous generator + function. When the code object is executed it returns an + asynchronous generator object. See :pep:`525` for more details. .. versionadded:: 3.6 @@ -1283,7 +1284,6 @@ for any introspection needs. - .. _inspect-module-cli: Command Line Interface -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 16:31:21 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 20:31:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjYwMTAp?= Message-ID: <20161020203120.33099.2259.4A51653C@psf.io> https://hg.python.org/cpython/rev/3821599fc74d changeset: 104591:3821599fc74d parent: 104589:79b9257f3386 parent: 104590:761414979de5 user: Yury Selivanov date: Thu Oct 20 16:31:15 2016 -0400 summary: Merge 3.6 (issue #26010) files: Doc/library/inspect.rst | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1253,25 +1253,26 @@ .. data:: CO_COROUTINE - The flag is set when the code object is a coroutine function, i.e. - a coroutine object is returned when the code object is executed. See - :pep:`492` for more details. + The flag is set when the code object is a coroutine function. + When the code object is executed it returns a coroutine object. + See :pep:`492` for more details. .. versionadded:: 3.5 .. data:: CO_ITERABLE_COROUTINE - Used to turn generators into generator-based coroutines. Generator - objects with this flag can be used in ``await`` expression, and can - ``yield from`` coroutine objects. See :pep:`492` for more details. + The flag is used to transform generators into generator-based + coroutines. Generator objects with this flag can be used in + ``await`` expression, and can ``yield from`` coroutine objects. + See :pep:`492` for more details. .. versionadded:: 3.5 .. data:: CO_ASYNC_GENERATOR - The flag is set when the code object is a asynchronous generator - function, i.e. an asynchronous generator object is returned when the - code object is executed. See :pep:`525` for more details. + The flag is set when the code object is an asynchronous generator + function. When the code object is executed it returns an + asynchronous generator object. See :pep:`525` for more details. .. versionadded:: 3.6 @@ -1283,7 +1284,6 @@ for any introspection needs. - .. _inspect-module-cli: Command Line Interface -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 16:33:43 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 20:33:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg0OTMp?= Message-ID: <20161020203343.38659.11375.410F4510@psf.io> https://hg.python.org/cpython/rev/74eb9c51d64e changeset: 104593:74eb9c51d64e parent: 104591:3821599fc74d parent: 104592:03528baa8c2c user: Yury Selivanov date: Thu Oct 20 16:33:39 2016 -0400 summary: Merge 3.6 (issue #28493) files: Modules/_asynciomodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -789,11 +789,11 @@ if (res != NULL) { /* The result of the Future is not an exception. - We cunstruct an exception instance manually with + We construct an exception instance manually with PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject (similarly to what genobject.c does). - This is to handle a situation when "res" is a tuple, in which + We do this to handle a situation when "res" is a tuple, in which case PyErr_SetObject would set the value of StopIteration to the first element of the tuple. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 16:33:43 2016 From: python-checkins at python.org (yury.selivanov) Date: Thu, 20 Oct 2016 20:33:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDkz?= =?utf-8?q?=3A_Fix_typos_in_=5Fasynciomodule=2Ec?= Message-ID: <20161020203343.11996.52814.58804320@psf.io> https://hg.python.org/cpython/rev/03528baa8c2c changeset: 104592:03528baa8c2c branch: 3.6 parent: 104590:761414979de5 user: Yury Selivanov date: Thu Oct 20 16:33:19 2016 -0400 summary: Issue #28493: Fix typos in _asynciomodule.c Thanks to St?phane Wirtel! files: Modules/_asynciomodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -789,11 +789,11 @@ if (res != NULL) { /* The result of the Future is not an exception. - We cunstruct an exception instance manually with + We construct an exception instance manually with PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject (similarly to what genobject.c does). - This is to handle a situation when "res" is a tuple, in which + We do this to handle a situation when "res" is a tuple, in which case PyErr_SetObject would set the value of StopIteration to the first element of the tuple. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 19:08:56 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 23:08:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_test_suite_fixes_from_3=2E6?= Message-ID: <20161020230856.68566.584.25DDF150@psf.io> https://hg.python.org/cpython/rev/091019c5e1fd changeset: 104596:091019c5e1fd parent: 104593:74eb9c51d64e parent: 104595:b811ec148337 user: Martin Panter date: Thu Oct 20 22:36:18 2016 +0000 summary: Merge test suite fixes from 3.6 files: Lib/test/test_capi.py | 1 + Lib/test/test_regrtest.py | 7 ++++++- Lib/test/test_socket.py | 1 + 3 files changed, 8 insertions(+), 1 deletions(-) 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 @@ -630,6 +630,7 @@ regex = regex.format(ptr=self.PTR_REGEX) self.assertRegex(out, regex) + @unittest.skipUnless(threading, 'Test requires a GIL (multithreading)') def check_malloc_without_gil(self, code): out = self.check(code) expected = ('Fatal Python error: Python memory allocator called ' diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -696,7 +696,12 @@ code = TEST_INTERRUPTED test = self.create_test("sigint", code=code) - for multiprocessing in (False, True): + try: + import threading + tests = (False, True) + except ImportError: + tests = (False,) + for multiprocessing in tests: if multiprocessing: args = ("--slowest", "-j2", test) else: 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 @@ -4569,6 +4569,7 @@ sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM, 0, sock0.fileno()) sock0.close() + self.addCleanup(sock.detach) with self.assertRaises(OSError): sock.setblocking(False) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 19:08:58 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 23:08:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDcx?= =?utf-8?q?=3A_Avoid_ResourceWarning_by_detaching_test_socket?= Message-ID: <20161020230855.9398.8354.9DDBE2E5@psf.io> https://hg.python.org/cpython/rev/2fd92794f775 changeset: 104594:2fd92794f775 branch: 3.6 parent: 104592:03528baa8c2c user: Martin Panter date: Thu Oct 20 07:44:29 2016 +0000 summary: Issue #28471: Avoid ResourceWarning by detaching test socket files: Lib/test/test_socket.py | 1 + 1 files changed, 1 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 @@ -4559,6 +4559,7 @@ sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM, 0, sock0.fileno()) sock0.close() + self.addCleanup(sock.detach) with self.assertRaises(OSError): sock.setblocking(False) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 19:08:58 2016 From: python-checkins at python.org (martin.panter) Date: Thu, 20 Oct 2016 23:08:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDg0?= =?utf-8?q?=3A_Skip_tests_if_GIL_is_not_used_or_multithreading_is_disabled?= Message-ID: <20161020230855.25236.16985.E72E3370@psf.io> https://hg.python.org/cpython/rev/b811ec148337 changeset: 104595:b811ec148337 branch: 3.6 user: Martin Panter date: Thu Oct 20 21:45:49 2016 +0000 summary: Issue #28484: Skip tests if GIL is not used or multithreading is disabled files: Lib/test/test_capi.py | 1 + Lib/test/test_regrtest.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletions(-) 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 @@ -630,6 +630,7 @@ regex = regex.format(ptr=self.PTR_REGEX) self.assertRegex(out, regex) + @unittest.skipUnless(threading, 'Test requires a GIL (multithreading)') def check_malloc_without_gil(self, code): out = self.check(code) expected = ('Fatal Python error: Python memory allocator called ' diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -696,7 +696,12 @@ code = TEST_INTERRUPTED test = self.create_test("sigint", code=code) - for multiprocessing in (False, True): + try: + import threading + tests = (False, True) + except ImportError: + tests = (False,) + for multiprocessing in tests: if multiprocessing: args = ("--slowest", "-j2", test) else: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 20:16:55 2016 From: python-checkins at python.org (martin.panter) Date: Fri, 21 Oct 2016 00:16:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323214=3A_Implemen?= =?utf-8?q?t_optional_BufferedReader=2C_BytesIO_read1=28=29_argument?= Message-ID: <20161021001655.27942.1978.95397B9A@psf.io> https://hg.python.org/cpython/rev/b6886ac88e28 changeset: 104597:b6886ac88e28 user: Martin Panter date: Thu Oct 20 23:48:14 2016 +0000 summary: Issue #23214: Implement optional BufferedReader, BytesIO read1() argument files: Doc/library/io.rst | 21 ++++++++++---- Lib/_pyio.py | 18 ++++++------ Lib/test/test_io.py | 16 ++++++++++- Lib/test/test_memoryio.py | 6 +-- Misc/NEWS | 4 ++ Modules/_io/bufferedio.c | 10 ++---- Modules/_io/bytesio.c | 6 ++-- Modules/_io/clinic/bufferedio.c.h | 13 +++++---- Modules/_io/clinic/bytesio.c.h | 26 ++++++++++++++++-- 9 files changed, 81 insertions(+), 39 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -477,7 +477,7 @@ A :exc:`BlockingIOError` is raised if the underlying raw stream is in non blocking-mode, and has no data available at the moment. - .. method:: read1(size=-1) + .. method:: read1([size]) Read and return up to *size* bytes, with at most one call to the underlying raw stream's :meth:`~RawIOBase.read` (or @@ -485,6 +485,9 @@ implementing your own buffering on top of a :class:`BufferedIOBase` object. + If *size* is ?1 (the default), an arbitrary number of bytes are + returned (more than zero unless EOF is reached). + .. method:: readinto(b) Read bytes into a pre-allocated, writable @@ -628,13 +631,16 @@ Return :class:`bytes` containing the entire contents of the buffer. - .. method:: read1() + .. method:: read1([size]) - In :class:`BytesIO`, this is the same as :meth:`read`. + In :class:`BytesIO`, this is the same as :meth:`~BufferedIOBase.read`. - .. method:: readinto1() + .. versionchanged:: 3.7 + The *size* argument is now optional. - In :class:`BytesIO`, this is the same as :meth:`readinto`. + .. method:: readinto1(b) + + In :class:`BytesIO`, this is the same as :meth:`~BufferedIOBase.readinto`. .. versionadded:: 3.5 @@ -664,12 +670,15 @@ Read and return *size* bytes, or if *size* is not given or negative, until EOF or if the read call would block in non-blocking mode. - .. method:: read1(size) + .. method:: read1([size]) Read and return up to *size* bytes with only one call on the raw stream. If at least one byte is buffered, only buffered bytes are returned. Otherwise, one raw stream read call is made. + .. versionchanged:: 3.7 + The *size* argument is now optional. + .. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE) diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -635,7 +635,7 @@ implementation, but wrap one. """ - def read(self, size=None): + def read(self, size=-1): """Read and return up to size bytes, where size is an int. If the argument is omitted, None, or negative, reads and @@ -655,7 +655,7 @@ """ self._unsupported("read") - def read1(self, size=None): + def read1(self, size=-1): """Read up to size bytes with at most one read() system call, where size is an int. """ @@ -863,7 +863,7 @@ self._buffer.clear() super().close() - def read(self, size=None): + def read(self, size=-1): if self.closed: raise ValueError("read from closed file") if size is None: @@ -877,7 +877,7 @@ self._pos = newpos return bytes(b) - def read1(self, size): + def read1(self, size=-1): """This is the same as read. """ return self.read(size) @@ -1073,12 +1073,12 @@ self._read_pos = 0 return self._read_buf[self._read_pos:] - def read1(self, size): + def read1(self, size=-1): """Reads up to size bytes, with at most one read() system call.""" # Returns up to size bytes. If at least one byte is buffered, we # only return buffered bytes. Otherwise, we do one raw read. if size < 0: - raise ValueError("number of bytes to read must be positive") + size = self.buffer_size if size == 0: return b"" with self._read_lock: @@ -1270,7 +1270,7 @@ self.reader = BufferedReader(reader, buffer_size) self.writer = BufferedWriter(writer, buffer_size) - def read(self, size=None): + def read(self, size=-1): if size is None: size = -1 return self.reader.read(size) @@ -1284,7 +1284,7 @@ def peek(self, size=0): return self.reader.peek(size) - def read1(self, size): + def read1(self, size=-1): return self.reader.read1(size) def readinto1(self, b): @@ -1370,7 +1370,7 @@ self.flush() return BufferedReader.peek(self, size) - def read1(self, size): + def read1(self, size=-1): self.flush() return BufferedReader.read1(self, size) 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 @@ -1146,6 +1146,7 @@ self.assertEqual(b"a", bufio.read(1)) self.assertEqual(b"b", bufio.read1(1)) self.assertEqual(rawio._reads, 1) + self.assertEqual(b"", bufio.read1(0)) self.assertEqual(b"c", bufio.read1(100)) self.assertEqual(rawio._reads, 1) self.assertEqual(b"d", bufio.read1(100)) @@ -1154,8 +1155,17 @@ self.assertEqual(rawio._reads, 3) self.assertEqual(b"", bufio.read1(100)) self.assertEqual(rawio._reads, 4) - # Invalid args - self.assertRaises(ValueError, bufio.read1, -1) + + def test_read1_arbitrary(self): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + self.assertEqual(b"a", bufio.read(1)) + self.assertEqual(b"bc", bufio.read1()) + self.assertEqual(b"d", bufio.read1()) + self.assertEqual(b"efg", bufio.read1(-1)) + self.assertEqual(rawio._reads, 3) + self.assertEqual(b"", bufio.read1()) + self.assertEqual(rawio._reads, 4) def test_readinto(self): rawio = self.MockRawIO((b"abc", b"d", b"efg")) @@ -1806,6 +1816,7 @@ pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) self.assertEqual(pair.read1(3), b"abc") + self.assertEqual(pair.read1(), b"def") def test_readinto(self): for method in ("readinto", "readinto1"): @@ -3467,6 +3478,7 @@ self.assertRaises(ValueError, f.read) if hasattr(f, "read1"): self.assertRaises(ValueError, f.read1, 1024) + self.assertRaises(ValueError, f.read1) if hasattr(f, "readall"): self.assertRaises(ValueError, f.readall) if hasattr(f, "readinto"): diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -437,10 +437,8 @@ def test_read1(self): buf = self.buftype("1234567890") - memio = self.ioclass(buf) - - self.assertRaises(TypeError, memio.read1) - self.assertEqual(memio.read(), buf) + self.assertEqual(self.ioclass(buf).read1(), buf) + self.assertEqual(self.ioclass(buf).read1(-1), buf) def test_readinto(self): buf = self.buftype("1234567890") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,10 @@ Library ------- +- Issue #23214: In the "io" module, the argument to BufferedReader and + BytesIO's read1() methods is now optional and can be -1, matching the + BufferedIOBase specification. + - Issue #28480: Fix error building socket module when multithreading is disabled. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -904,7 +904,7 @@ CHECK_INITIALIZED(self) if (n < -1) { PyErr_SetString(PyExc_ValueError, - "read length must be positive or -1"); + "read length must be non-negative or -1"); return NULL; } @@ -932,22 +932,20 @@ /*[clinic input] _io._Buffered.read1 - size as n: Py_ssize_t + size as n: Py_ssize_t = -1 / [clinic start generated code]*/ static PyObject * _io__Buffered_read1_impl(buffered *self, Py_ssize_t n) -/*[clinic end generated code: output=bcc4fb4e54d103a3 input=8d2869c18b983184]*/ +/*[clinic end generated code: output=bcc4fb4e54d103a3 input=7d22de9630b61774]*/ { Py_ssize_t have, r; PyObject *res = NULL; CHECK_INITIALIZED(self) if (n < 0) { - PyErr_SetString(PyExc_ValueError, - "read length must be positive"); - return NULL; + n = self->buffer_size; } CHECK_CLOSED(self, "read of closed file") diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -420,7 +420,7 @@ /*[clinic input] _io.BytesIO.read1 - size: object + size: object(c_default="Py_None") = -1 / Read at most size bytes, returned as a bytes object. @@ -430,8 +430,8 @@ [clinic start generated code]*/ static PyObject * -_io_BytesIO_read1(bytesio *self, PyObject *size) -/*[clinic end generated code: output=16021f5d0ac3d4e2 input=d4f40bb8f2f99418]*/ +_io_BytesIO_read1_impl(bytesio *self, PyObject *size) +/*[clinic end generated code: output=a60d80c84c81a6b8 input=0951874bafee8e80]*/ { return _io_BytesIO_read_impl(self, size); } diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -140,23 +140,24 @@ } PyDoc_STRVAR(_io__Buffered_read1__doc__, -"read1($self, size, /)\n" +"read1($self, size=-1, /)\n" "--\n" "\n"); #define _IO__BUFFERED_READ1_METHODDEF \ - {"read1", (PyCFunction)_io__Buffered_read1, METH_O, _io__Buffered_read1__doc__}, + {"read1", (PyCFunction)_io__Buffered_read1, METH_VARARGS, _io__Buffered_read1__doc__}, static PyObject * _io__Buffered_read1_impl(buffered *self, Py_ssize_t n); static PyObject * -_io__Buffered_read1(buffered *self, PyObject *arg) +_io__Buffered_read1(buffered *self, PyObject *args) { PyObject *return_value = NULL; - Py_ssize_t n; + Py_ssize_t n = -1; - if (!PyArg_Parse(arg, "n:read1", &n)) { + if (!PyArg_ParseTuple(args, "|n:read1", + &n)) { goto exit; } return_value = _io__Buffered_read1_impl(self, n); @@ -475,4 +476,4 @@ exit: return return_value; } -/*[clinic end generated code: output=a956f394ecde4cf9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=490c97bfcfd92c51 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -181,7 +181,7 @@ } PyDoc_STRVAR(_io_BytesIO_read1__doc__, -"read1($self, size, /)\n" +"read1($self, size=-1, /)\n" "--\n" "\n" "Read at most size bytes, returned as a bytes object.\n" @@ -190,7 +190,27 @@ "Return an empty bytes object at EOF."); #define _IO_BYTESIO_READ1_METHODDEF \ - {"read1", (PyCFunction)_io_BytesIO_read1, METH_O, _io_BytesIO_read1__doc__}, + {"read1", (PyCFunction)_io_BytesIO_read1, METH_VARARGS, _io_BytesIO_read1__doc__}, + +static PyObject * +_io_BytesIO_read1_impl(bytesio *self, PyObject *size); + +static PyObject * +_io_BytesIO_read1(bytesio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *size = Py_None; + + if (!PyArg_UnpackTuple(args, "read1", + 0, 1, + &size)) { + goto exit; + } + return_value = _io_BytesIO_read1_impl(self, size); + +exit: + return return_value; +} PyDoc_STRVAR(_io_BytesIO_readline__doc__, "readline($self, size=None, /)\n" @@ -428,4 +448,4 @@ exit: return return_value; } -/*[clinic end generated code: output=6382e8eb578eea64 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8f469431da1b3857 input=a9049054013a1b77]*/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 22:00:14 2016 From: python-checkins at python.org (martin.panter) Date: Fri, 21 Oct 2016 02:00:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323214=3A_Remove_B?= =?utf-8?q?ufferedReader=2Eread1=28-1=29_workaround?= Message-ID: <20161021020014.18383.87973.4705BA20@psf.io> https://hg.python.org/cpython/rev/d4fce64b1c65 changeset: 104598:d4fce64b1c65 user: Martin Panter date: Fri Oct 21 00:52:04 2016 +0000 summary: Issue #23214: Remove BufferedReader.read1(-1) workaround files: Lib/http/client.py | 9 +-------- 1 files changed, 1 insertions(+), 8 deletions(-) diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -642,14 +642,7 @@ return self._read1_chunked(n) if self.length is not None and (n < 0 or n > self.length): n = self.length - try: - result = self.fp.read1(n) - except ValueError: - if n >= 0: - raise - # some implementations, like BufferedReader, don't support -1 - # Read an arbitrarily selected largeish chunk. - result = self.fp.read1(16*1024) + result = self.fp.read1(n) if not result and n: self._close_conn() elif self.length is not None: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 23:33:09 2016 From: python-checkins at python.org (inada.naoki) Date: Fri, 21 Oct 2016 03:33:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDQ4?= =?utf-8?q?=3A_Fix_C_implemented_asyncio=2EFuture_didn=27t_work_on_Windows?= Message-ID: <20161021033309.9581.70398.D2430A46@psf.io> https://hg.python.org/cpython/rev/6d20d6fe9b41 changeset: 104599:6d20d6fe9b41 branch: 3.6 parent: 104595:b811ec148337 user: INADA Naoki date: Fri Oct 21 12:30:15 2016 +0900 summary: Issue #28448: Fix C implemented asyncio.Future didn't work on Windows files: Lib/asyncio/futures.py | 8 +- Lib/asyncio/windows_events.py | 9 +- Misc/NEWS | 2 + PCbuild/_asyncio.vcxproj | 77 ++++++++++++++++++++ PCbuild/_asyncio.vcxproj.filters | 16 ++++ PCbuild/pcbuild.proj | 2 +- PCbuild/pcbuild.sln | 2 + PCbuild/pythoncore.vcxproj | 1 - 8 files changed, 109 insertions(+), 8 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -247,10 +247,10 @@ if self._state != _PENDING: return False self._state = _CANCELLED - self._schedule_callbacks() + self.__schedule_callbacks() return True - def _schedule_callbacks(self): + def __schedule_callbacks(self): """Internal: Ask the event loop to call all callbacks. The callbacks are scheduled to be called as soon as possible. Also @@ -352,7 +352,7 @@ raise InvalidStateError('{}: {!r}'.format(self._state, self)) self._result = result self._state = _FINISHED - self._schedule_callbacks() + self.__schedule_callbacks() def set_exception(self, exception): """Mark the future done and set an exception. @@ -369,7 +369,7 @@ "and cannot be raised into a Future") self._exception = exception self._state = _FINISHED - self._schedule_callbacks() + self.__schedule_callbacks() if compat.PY34: self._log_traceback = True else: diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -171,8 +171,13 @@ def cancel(self): raise RuntimeError("_WaitCancelFuture must not be cancelled") - def _schedule_callbacks(self): - super(_WaitCancelFuture, self)._schedule_callbacks() + def set_result(self, result): + super().set_result(result) + if self._done_callback is not None: + self._done_callback(self) + + def set_exception(self, exception): + super().set_exception(exception) if self._done_callback is not None: self._done_callback(self) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,8 @@ Library ------- +- Issue #28448: Fix C implemented asyncio.Future didn't work on Windows. + - Issue #28480: Fix error building socket module when multithreading is disabled. diff --git a/PCbuild/_asyncio.vcxproj b/PCbuild/_asyncio.vcxproj new file mode 100644 --- /dev/null +++ b/PCbuild/_asyncio.vcxproj @@ -0,0 +1,77 @@ +? + + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + Win32 + + + Release + x64 + + + + {384C224A-7474-476E-A01B-750EA7DE918C} + _asyncio + Win32Proj + + + + + DynamicLibrary + NotSet + + + + .pyd + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + false + + + + + + diff --git a/PCbuild/_asyncio.vcxproj.filters b/PCbuild/_asyncio.vcxproj.filters new file mode 100644 --- /dev/null +++ b/PCbuild/_asyncio.vcxproj.filters @@ -0,0 +1,16 @@ +? + + + + + + + {2422278e-eeeb-4241-8182-433e2bc5a7fc} + + + + + Source Files + + + \ No newline at end of file diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -51,7 +51,7 @@ - + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -94,6 +94,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testconsole", "_testconsole.vcxproj", "{B244E787-C445-441C-BDF4-5A4F1A3A1E51}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_asyncio", "_asyncio.vcxproj", "{384C224A-7474-476E-A01B-750EA7DE918C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -213,7 +213,6 @@ - -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 20 23:33:09 2016 From: python-checkins at python.org (inada.naoki) Date: Fri, 21 Oct 2016 03:33:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328448=3A_Fix_C_implemented_asyncio=2EFuture_did?= =?utf-8?q?n=27t_work_on_Windows_=28merge?= Message-ID: <20161021033309.38778.23180.8E4360AC@psf.io> https://hg.python.org/cpython/rev/a9a136c9d857 changeset: 104600:a9a136c9d857 parent: 104598:d4fce64b1c65 parent: 104599:6d20d6fe9b41 user: INADA Naoki date: Fri Oct 21 12:32:46 2016 +0900 summary: Issue #28448: Fix C implemented asyncio.Future didn't work on Windows (merge 3.6) files: Lib/asyncio/futures.py | 8 +- Lib/asyncio/windows_events.py | 9 +- Misc/NEWS | 2 + PCbuild/_asyncio.vcxproj | 77 ++++++++++++++++++++ PCbuild/_asyncio.vcxproj.filters | 16 ++++ PCbuild/pcbuild.proj | 2 +- PCbuild/pcbuild.sln | 2 + PCbuild/pythoncore.vcxproj | 1 - 8 files changed, 109 insertions(+), 8 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -247,10 +247,10 @@ if self._state != _PENDING: return False self._state = _CANCELLED - self._schedule_callbacks() + self.__schedule_callbacks() return True - def _schedule_callbacks(self): + def __schedule_callbacks(self): """Internal: Ask the event loop to call all callbacks. The callbacks are scheduled to be called as soon as possible. Also @@ -352,7 +352,7 @@ raise InvalidStateError('{}: {!r}'.format(self._state, self)) self._result = result self._state = _FINISHED - self._schedule_callbacks() + self.__schedule_callbacks() def set_exception(self, exception): """Mark the future done and set an exception. @@ -369,7 +369,7 @@ "and cannot be raised into a Future") self._exception = exception self._state = _FINISHED - self._schedule_callbacks() + self.__schedule_callbacks() if compat.PY34: self._log_traceback = True else: diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -171,8 +171,13 @@ def cancel(self): raise RuntimeError("_WaitCancelFuture must not be cancelled") - def _schedule_callbacks(self): - super(_WaitCancelFuture, self)._schedule_callbacks() + def set_result(self, result): + super().set_result(result) + if self._done_callback is not None: + self._done_callback(self) + + def set_exception(self, exception): + super().set_exception(exception) if self._done_callback is not None: self._done_callback(self) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,8 @@ Library ------- +- Issue #28448: Fix C implemented asyncio.Future didn't work on Windows. + - Issue #23214: In the "io" module, the argument to BufferedReader and BytesIO's read1() methods is now optional and can be -1, matching the BufferedIOBase specification. diff --git a/PCbuild/_asyncio.vcxproj b/PCbuild/_asyncio.vcxproj new file mode 100644 --- /dev/null +++ b/PCbuild/_asyncio.vcxproj @@ -0,0 +1,77 @@ +? + + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + Win32 + + + Release + x64 + + + + {384C224A-7474-476E-A01B-750EA7DE918C} + _asyncio + Win32Proj + + + + + DynamicLibrary + NotSet + + + + .pyd + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + false + + + + + + diff --git a/PCbuild/_asyncio.vcxproj.filters b/PCbuild/_asyncio.vcxproj.filters new file mode 100644 --- /dev/null +++ b/PCbuild/_asyncio.vcxproj.filters @@ -0,0 +1,16 @@ +? + + + + + + + {2422278e-eeeb-4241-8182-433e2bc5a7fc} + + + + + Source Files + + + \ No newline at end of file diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -51,7 +51,7 @@ - + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -94,6 +94,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testconsole", "_testconsole.vcxproj", "{B244E787-C445-441C-BDF4-5A4F1A3A1E51}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_asyncio", "_asyncio.vcxproj", "{384C224A-7474-476E-A01B-750EA7DE918C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -213,7 +213,6 @@ - -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 01:39:48 2016 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 21 Oct 2016 05:39:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_mark_dtrace_st?= =?utf-8?q?ubs_as_static_inline=3B_remove_stubs?= Message-ID: <20161021053947.16715.91034.4BCE2F77@psf.io> https://hg.python.org/cpython/rev/fd9a4bd16587 changeset: 104601:fd9a4bd16587 branch: 3.6 parent: 104599:6d20d6fe9b41 user: Benjamin Peterson date: Thu Oct 20 22:37:00 2016 -0700 summary: mark dtrace stubs as static inline; remove stubs C99 inline semantics don't work everywhere. (https://bugs.python.org/issue28092) We don't want these to have external visibility anyway. files: Include/pydtrace.h | 36 +++++++++--------- Makefile.pre.in | 1 - PCbuild/pythoncore.vcxproj | 1 - PCbuild/pythoncore.vcxproj.filters | 3 - Python/dtrace_stubs.c | 24 ------------ 5 files changed, 18 insertions(+), 47 deletions(-) diff --git a/Include/pydtrace.h b/Include/pydtrace.h --- a/Include/pydtrace.h +++ b/Include/pydtrace.h @@ -25,25 +25,25 @@ /* Without DTrace, compile to nothing. */ -inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2) {} -inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2) {} -inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2) {} -inline void PyDTrace_GC_START(int arg0) {} -inline void PyDTrace_GC_DONE(int arg0) {} -inline void PyDTrace_INSTANCE_NEW_START(int arg0) {} -inline void PyDTrace_INSTANCE_NEW_DONE(int arg0) {} -inline void PyDTrace_INSTANCE_DELETE_START(int arg0) {} -inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {} +static inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2) {} +static inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2) {} +static inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2) {} +static inline void PyDTrace_GC_START(int arg0) {} +static inline void PyDTrace_GC_DONE(int arg0) {} +static inline void PyDTrace_INSTANCE_NEW_START(int arg0) {} +static inline void PyDTrace_INSTANCE_NEW_DONE(int arg0) {} +static inline void PyDTrace_INSTANCE_DELETE_START(int arg0) {} +static inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {} -inline int PyDTrace_LINE_ENABLED(void) { return 0; } -inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; } -inline int PyDTrace_FUNCTION_RETURN_ENABLED(void) { return 0; } -inline int PyDTrace_GC_START_ENABLED(void) { return 0; } -inline int PyDTrace_GC_DONE_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void) { return 0; } +static inline int PyDTrace_LINE_ENABLED(void) { return 0; } +static inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; } +static inline int PyDTrace_FUNCTION_RETURN_ENABLED(void) { return 0; } +static inline int PyDTrace_GC_START_ENABLED(void) { return 0; } +static inline int PyDTrace_GC_DONE_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void) { return 0; } #endif /* !WITH_DTRACE */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -355,7 +355,6 @@ Python/compile.o \ Python/codecs.o \ Python/dynamic_annotations.o \ - Python/dtrace_stubs.o \ Python/errors.o \ Python/frozenmain.o \ Python/future.o \ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -356,7 +356,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -851,9 +851,6 @@ Python - - Python - Python diff --git a/Python/dtrace_stubs.c b/Python/dtrace_stubs.c deleted file mode 100644 --- a/Python/dtrace_stubs.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include "pydtrace.h" - -#ifndef WITH_DTRACE -extern inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2); -extern inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2); -extern inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2); -extern inline void PyDTrace_GC_START(int arg0); -extern inline void PyDTrace_GC_DONE(int arg0); -extern inline void PyDTrace_INSTANCE_NEW_START(int arg0); -extern inline void PyDTrace_INSTANCE_NEW_DONE(int arg0); -extern inline void PyDTrace_INSTANCE_DELETE_START(int arg0); -extern inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0); - -extern inline int PyDTrace_LINE_ENABLED(void); -extern inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void); -extern inline int PyDTrace_FUNCTION_RETURN_ENABLED(void); -extern inline int PyDTrace_GC_START_ENABLED(void); -extern inline int PyDTrace_GC_DONE_ENABLED(void); -extern inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void); -extern inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void); -extern inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void); -extern inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void); -#endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 01:39:52 2016 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 21 Oct 2016 05:39:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42?= Message-ID: <20161021053947.18199.79572.09658045@psf.io> https://hg.python.org/cpython/rev/307d7b47b06a changeset: 104602:307d7b47b06a parent: 104600:a9a136c9d857 parent: 104601:fd9a4bd16587 user: Benjamin Peterson date: Thu Oct 20 22:39:39 2016 -0700 summary: merge 3.6 files: Include/pydtrace.h | 36 +++++++++--------- Makefile.pre.in | 1 - PCbuild/pythoncore.vcxproj | 1 - PCbuild/pythoncore.vcxproj.filters | 3 - Python/dtrace_stubs.c | 24 ------------ 5 files changed, 18 insertions(+), 47 deletions(-) diff --git a/Include/pydtrace.h b/Include/pydtrace.h --- a/Include/pydtrace.h +++ b/Include/pydtrace.h @@ -25,25 +25,25 @@ /* Without DTrace, compile to nothing. */ -inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2) {} -inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2) {} -inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2) {} -inline void PyDTrace_GC_START(int arg0) {} -inline void PyDTrace_GC_DONE(int arg0) {} -inline void PyDTrace_INSTANCE_NEW_START(int arg0) {} -inline void PyDTrace_INSTANCE_NEW_DONE(int arg0) {} -inline void PyDTrace_INSTANCE_DELETE_START(int arg0) {} -inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {} +static inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2) {} +static inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2) {} +static inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2) {} +static inline void PyDTrace_GC_START(int arg0) {} +static inline void PyDTrace_GC_DONE(int arg0) {} +static inline void PyDTrace_INSTANCE_NEW_START(int arg0) {} +static inline void PyDTrace_INSTANCE_NEW_DONE(int arg0) {} +static inline void PyDTrace_INSTANCE_DELETE_START(int arg0) {} +static inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {} -inline int PyDTrace_LINE_ENABLED(void) { return 0; } -inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; } -inline int PyDTrace_FUNCTION_RETURN_ENABLED(void) { return 0; } -inline int PyDTrace_GC_START_ENABLED(void) { return 0; } -inline int PyDTrace_GC_DONE_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void) { return 0; } -inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void) { return 0; } +static inline int PyDTrace_LINE_ENABLED(void) { return 0; } +static inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; } +static inline int PyDTrace_FUNCTION_RETURN_ENABLED(void) { return 0; } +static inline int PyDTrace_GC_START_ENABLED(void) { return 0; } +static inline int PyDTrace_GC_DONE_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void) { return 0; } +static inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void) { return 0; } #endif /* !WITH_DTRACE */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -355,7 +355,6 @@ Python/compile.o \ Python/codecs.o \ Python/dynamic_annotations.o \ - Python/dtrace_stubs.o \ Python/errors.o \ Python/frozenmain.o \ Python/future.o \ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -356,7 +356,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -851,9 +851,6 @@ Python - - Python - Python diff --git a/Python/dtrace_stubs.c b/Python/dtrace_stubs.c deleted file mode 100644 --- a/Python/dtrace_stubs.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include "pydtrace.h" - -#ifndef WITH_DTRACE -extern inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2); -extern inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2); -extern inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2); -extern inline void PyDTrace_GC_START(int arg0); -extern inline void PyDTrace_GC_DONE(int arg0); -extern inline void PyDTrace_INSTANCE_NEW_START(int arg0); -extern inline void PyDTrace_INSTANCE_NEW_DONE(int arg0); -extern inline void PyDTrace_INSTANCE_DELETE_START(int arg0); -extern inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0); - -extern inline int PyDTrace_LINE_ENABLED(void); -extern inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void); -extern inline int PyDTrace_FUNCTION_RETURN_ENABLED(void); -extern inline int PyDTrace_GC_START_ENABLED(void); -extern inline int PyDTrace_GC_DONE_ENABLED(void); -extern inline int PyDTrace_INSTANCE_NEW_START_ENABLED(void); -extern inline int PyDTrace_INSTANCE_NEW_DONE_ENABLED(void); -extern inline int PyDTrace_INSTANCE_DELETE_START_ENABLED(void); -extern inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void); -#endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 08:18:06 2016 From: python-checkins at python.org (inada.naoki) Date: Fri, 21 Oct 2016 12:18:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzE4MjE5?= =?utf-8?q?=3A_Optimize_csv=2EDictWriter_for_large_number_of_columns=2E?= Message-ID: <20161021105338.18199.62572.A88755AC@psf.io> https://hg.python.org/cpython/rev/1928074e6519 changeset: 104603:1928074e6519 branch: 3.6 parent: 104601:fd9a4bd16587 user: INADA Naoki date: Fri Oct 21 19:47:57 2016 +0900 summary: Issue #18219: Optimize csv.DictWriter for large number of columns. Patch by Mariatta Wijaya. files: Doc/library/csv.rst | 10 ++++++---- Lib/csv.py | 2 +- Lib/test/test_csv.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -195,10 +195,12 @@ written if the dictionary is missing a key in *fieldnames*. If the dictionary passed to the :meth:`writerow` method contains a key not found in *fieldnames*, the optional *extrasaction* parameter indicates what action to - take. If it is set to ``'raise'`` a :exc:`ValueError` is raised. If it is - set to ``'ignore'``, extra values in the dictionary are ignored. Any other - optional or keyword arguments are passed to the underlying :class:`writer` - instance. + take. + If it is set to ``'raise'``, the default value, a :exc:`ValueError` + is raised. + If it is set to ``'ignore'``, extra values in the dictionary are ignored. + Any other optional or keyword arguments are passed to the underlying + :class:`writer` instance. Note that unlike the :class:`DictReader` class, the *fieldnames* parameter of the :class:`DictWriter` is not optional. Since Python's :class:`dict` diff --git a/Lib/csv.py b/Lib/csv.py --- a/Lib/csv.py +++ b/Lib/csv.py @@ -145,7 +145,7 @@ def _dict_to_list(self, rowdict): if self.extrasaction == "raise": - wrong_fields = [k for k in rowdict if k not in self.fieldnames] + wrong_fields = rowdict.keys() - self.fieldnames if wrong_fields: raise ValueError("dict contains fields not in fieldnames: " + ", ".join([repr(x) for x in wrong_fields])) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -626,6 +626,24 @@ self.assertNotIn("'f2'", exception) self.assertIn("1", exception) + def test_typo_in_extrasaction_raises_error(self): + fileobj = StringIO() + self.assertRaises(ValueError, csv.DictWriter, fileobj, ['f1', 'f2'], + extrasaction="raised") + + def test_write_field_not_in_field_names_raise(self): + fileobj = StringIO() + writer = csv.DictWriter(fileobj, ['f1', 'f2'], extrasaction="raise") + dictrow = {'f0': 0, 'f1': 1, 'f2': 2, 'f3': 3} + self.assertRaises(ValueError, csv.DictWriter.writerow, writer, dictrow) + + def test_write_field_not_in_field_names_ignore(self): + fileobj = StringIO() + writer = csv.DictWriter(fileobj, ['f1', 'f2'], extrasaction="ignore") + dictrow = {'f0': 0, 'f1': 1, 'f2': 2, 'f3': 3} + csv.DictWriter.writerow(writer, dictrow) + self.assertEqual(fileobj.getvalue(), "1,2\r\n") + def test_read_dict_fields(self): with TemporaryFile("w+") as fileobj: fileobj.write("1,2,abc\r\n") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,9 @@ Library ------- +- Issue #18219: Optimize csv.DictWriter for large number of columns. + Patch by Mariatta Wijaya. + - Issue #28448: Fix C implemented asyncio.Future didn't work on Windows. - Issue #28480: Fix error building socket module when multithreading is -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 08:18:06 2016 From: python-checkins at python.org (inada.naoki) Date: Fri, 21 Oct 2016 12:18:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318219=3A_Optimize_csv=2EDictWriter_for_large_nu?= =?utf-8?q?mber_of_columns=2E?= Message-ID: <20161021105338.27271.75031.ACF6F127@psf.io> https://hg.python.org/cpython/rev/6f1602dfa4d5 changeset: 104604:6f1602dfa4d5 parent: 104602:307d7b47b06a parent: 104603:1928074e6519 user: INADA Naoki date: Fri Oct 21 19:53:30 2016 +0900 summary: Issue #18219: Optimize csv.DictWriter for large number of columns. Patch by Mariatta Wijaya. files: Doc/library/csv.rst | 10 ++++++---- Lib/csv.py | 2 +- Lib/test/test_csv.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -195,10 +195,12 @@ written if the dictionary is missing a key in *fieldnames*. If the dictionary passed to the :meth:`writerow` method contains a key not found in *fieldnames*, the optional *extrasaction* parameter indicates what action to - take. If it is set to ``'raise'`` a :exc:`ValueError` is raised. If it is - set to ``'ignore'``, extra values in the dictionary are ignored. Any other - optional or keyword arguments are passed to the underlying :class:`writer` - instance. + take. + If it is set to ``'raise'``, the default value, a :exc:`ValueError` + is raised. + If it is set to ``'ignore'``, extra values in the dictionary are ignored. + Any other optional or keyword arguments are passed to the underlying + :class:`writer` instance. Note that unlike the :class:`DictReader` class, the *fieldnames* parameter of the :class:`DictWriter` is not optional. Since Python's :class:`dict` diff --git a/Lib/csv.py b/Lib/csv.py --- a/Lib/csv.py +++ b/Lib/csv.py @@ -145,7 +145,7 @@ def _dict_to_list(self, rowdict): if self.extrasaction == "raise": - wrong_fields = [k for k in rowdict if k not in self.fieldnames] + wrong_fields = rowdict.keys() - self.fieldnames if wrong_fields: raise ValueError("dict contains fields not in fieldnames: " + ", ".join([repr(x) for x in wrong_fields])) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -626,6 +626,24 @@ self.assertNotIn("'f2'", exception) self.assertIn("1", exception) + def test_typo_in_extrasaction_raises_error(self): + fileobj = StringIO() + self.assertRaises(ValueError, csv.DictWriter, fileobj, ['f1', 'f2'], + extrasaction="raised") + + def test_write_field_not_in_field_names_raise(self): + fileobj = StringIO() + writer = csv.DictWriter(fileobj, ['f1', 'f2'], extrasaction="raise") + dictrow = {'f0': 0, 'f1': 1, 'f2': 2, 'f3': 3} + self.assertRaises(ValueError, csv.DictWriter.writerow, writer, dictrow) + + def test_write_field_not_in_field_names_ignore(self): + fileobj = StringIO() + writer = csv.DictWriter(fileobj, ['f1', 'f2'], extrasaction="ignore") + dictrow = {'f0': 0, 'f1': 1, 'f2': 2, 'f3': 3} + csv.DictWriter.writerow(writer, dictrow) + self.assertEqual(fileobj.getvalue(), "1,2\r\n") + def test_read_dict_fields(self): with TemporaryFile("w+") as fileobj: fileobj.write("1,2,abc\r\n") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ Library ------- +- Issue #18219: Optimize csv.DictWriter for large number of columns. + Patch by Mariatta Wijaya. + - Issue #28448: Fix C implemented asyncio.Future didn't work on Windows. - Issue #23214: In the "io" module, the argument to BufferedReader and -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 09:21:34 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 13:21:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDEw?= =?utf-8?q?=3A_Keep_the_traceback_of_original_exception_in?= Message-ID: <20161021132133.68321.21678.EC2BDFD1@psf.io> https://hg.python.org/cpython/rev/81666d3e4a37 changeset: 104605:81666d3e4a37 branch: 3.5 parent: 104584:2b089035a453 user: Serhiy Storchaka date: Fri Oct 21 16:19:59 2016 +0300 summary: Issue #28410: Keep the traceback of original exception in _PyErr_ChainExceptions(). files: Python/errors.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -388,8 +388,11 @@ PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } Py_DECREF(exc); - Py_XDECREF(tb); PyErr_NormalizeException(&exc2, &val2, &tb2); PyException_SetContext(val2, val); PyErr_Restore(exc2, val2, tb2); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 09:21:34 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 13:21:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328410=3A_Keep_the_traceback_of_original_exception_in?= Message-ID: <20161021132134.110755.24975.113AB6D4@psf.io> https://hg.python.org/cpython/rev/23a1d9ec35d5 changeset: 104606:23a1d9ec35d5 branch: 3.6 parent: 104603:1928074e6519 parent: 104605:81666d3e4a37 user: Serhiy Storchaka date: Fri Oct 21 16:20:43 2016 +0300 summary: Issue #28410: Keep the traceback of original exception in _PyErr_ChainExceptions(). files: Python/errors.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -387,8 +387,11 @@ PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } Py_DECREF(exc); - Py_XDECREF(tb); PyErr_NormalizeException(&exc2, &val2, &tb2); PyException_SetContext(val2, val); PyErr_Restore(exc2, val2, tb2); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 09:21:34 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 13:21:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328410=3A_Keep_the_traceback_of_original_excepti?= =?utf-8?q?on_in?= Message-ID: <20161021132134.68345.93318.D0061C17@psf.io> https://hg.python.org/cpython/rev/e853492da42c changeset: 104607:e853492da42c parent: 104604:6f1602dfa4d5 parent: 104606:23a1d9ec35d5 user: Serhiy Storchaka date: Fri Oct 21 16:21:02 2016 +0300 summary: Issue #28410: Keep the traceback of original exception in _PyErr_ChainExceptions(). files: Python/errors.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -387,8 +387,11 @@ PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } Py_DECREF(exc); - Py_XDECREF(tb); PyErr_NormalizeException(&exc2, &val2, &tb2); PyException_SetContext(val2, val); PyErr_Restore(exc2, val2, tb2); -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Fri Oct 21 09:21:37 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 21 Oct 2016 14:21:37 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-21 Message-ID: <42d56211-39f5-4e30-8246-028ca7275c15@irsmsx103.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-21 02:47:27 +0000 commit: cca20d28f348 previous commit: ddf32a646457 revision date: 2016-10-20 19:41:11 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% -0.94% 4.22% 4.29% :-) pybench 0.18% 0.04% 6.10% 3.34% :-( regex_v8 0.65% 0.00% -2.09% 11.13% :-) nbody 0.07% -0.01% 7.95% -0.13% :-) json_dump_v2 0.30% -0.18% 2.37% 8.39% :-| normal_startup 0.76% 0.32% 0.00% 1.86% :-) ssbench 0.25% -0.09% 2.08% 2.21% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-21/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Fri Oct 21 09:22:32 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 21 Oct 2016 14:22:32 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-21 Message-ID: Results for project Python default, build date 2016-10-21 02:01:17 +0000 commit: b6886ac88e28 previous commit: 1ce50f7027c1 revision date: 2016-10-20 23:48:14 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.17% -0.23% 6.23% 14.88% :-) pybench 0.12% 0.10% 5.35% 3.95% :-( regex_v8 3.69% -0.00% -3.38% 4.79% :-) nbody 0.27% 0.12% 4.30% 4.39% :-( json_dump_v2 0.35% -0.95% -11.81% 15.87% :-| normal_startup 1.00% 1.26% 1.72% 6.40% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-21/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Fri Oct 21 10:15:47 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 14:15:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MjE0?= =?utf-8?q?=3A_Improved_exception_reporting_for_problematic_=5F=5Fset=5Fna?= =?utf-8?q?me=5F=5F?= Message-ID: <20161021141546.16753.38519.F7F2C587@psf.io> https://hg.python.org/cpython/rev/f7e1e39ccddd changeset: 104610:f7e1e39ccddd branch: 3.6 parent: 104608:969c8bfe8872 user: Serhiy Storchaka date: Fri Oct 21 17:13:31 2016 +0300 summary: Issue #28214: Improved exception reporting for problematic __set_name__ attributes. files: Lib/test/test_subclassinit.py | 26 ++++++++++++++++------ Misc/NEWS | 3 ++ Objects/typeobject.c | 7 +++++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_subclassinit.py b/Lib/test/test_subclassinit.py --- a/Lib/test/test_subclassinit.py +++ b/Lib/test/test_subclassinit.py @@ -133,20 +133,32 @@ def test_set_name_error(self): class Descriptor: def __set_name__(self, owner, name): - raise RuntimeError + 1/0 - with self.assertRaises(RuntimeError): - class A: - d = Descriptor() + with self.assertRaises(RuntimeError) as cm: + class NotGoingToWork: + attr = Descriptor() + + exc = cm.exception + self.assertRegex(str(exc), r'\bNotGoingToWork\b') + self.assertRegex(str(exc), r'\battr\b') + self.assertRegex(str(exc), r'\bDescriptor\b') + self.assertIsInstance(exc.__cause__, ZeroDivisionError) def test_set_name_wrong(self): class Descriptor: def __set_name__(self): pass - with self.assertRaises(TypeError): - class A: - d = Descriptor() + with self.assertRaises(RuntimeError) as cm: + class NotGoingToWork: + attr = Descriptor() + + exc = cm.exception + self.assertRegex(str(exc), r'\bNotGoingToWork\b') + self.assertRegex(str(exc), r'\battr\b') + self.assertRegex(str(exc), r'\bDescriptor\b') + self.assertIsInstance(exc.__cause__, TypeError) def test_set_name_lookup(self): resolved = [] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28214: Improved exception reporting for problematic __set_name__ + attributes. + - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7022,8 +7022,13 @@ if (set_name != NULL) { tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); Py_DECREF(set_name); - if (tmp == NULL) + if (tmp == NULL) { + _PyErr_FormatFromCause(PyExc_RuntimeError, + "Error calling __set_name__ on '%.100s' instance %R " + "in '%.100s'", + value->ob_type->tp_name, key, type->tp_name); return -1; + } else Py_DECREF(tmp); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 10:15:47 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 14:15:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328214=3A_Improved_exception_reporting_for_probl?= =?utf-8?b?ZW1hdGljIF9fc2V0X25hbWVfXw==?= Message-ID: <20161021141547.110671.74137.CE31C353@psf.io> https://hg.python.org/cpython/rev/7c3ec24f4582 changeset: 104611:7c3ec24f4582 parent: 104609:2119cb0beace parent: 104610:f7e1e39ccddd user: Serhiy Storchaka date: Fri Oct 21 17:15:20 2016 +0300 summary: Issue #28214: Improved exception reporting for problematic __set_name__ attributes. files: Lib/test/test_subclassinit.py | 26 ++++++++++++++++------ Misc/NEWS | 3 ++ Objects/typeobject.c | 7 +++++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_subclassinit.py b/Lib/test/test_subclassinit.py --- a/Lib/test/test_subclassinit.py +++ b/Lib/test/test_subclassinit.py @@ -133,20 +133,32 @@ def test_set_name_error(self): class Descriptor: def __set_name__(self, owner, name): - raise RuntimeError + 1/0 - with self.assertRaises(RuntimeError): - class A: - d = Descriptor() + with self.assertRaises(RuntimeError) as cm: + class NotGoingToWork: + attr = Descriptor() + + exc = cm.exception + self.assertRegex(str(exc), r'\bNotGoingToWork\b') + self.assertRegex(str(exc), r'\battr\b') + self.assertRegex(str(exc), r'\bDescriptor\b') + self.assertIsInstance(exc.__cause__, ZeroDivisionError) def test_set_name_wrong(self): class Descriptor: def __set_name__(self): pass - with self.assertRaises(TypeError): - class A: - d = Descriptor() + with self.assertRaises(RuntimeError) as cm: + class NotGoingToWork: + attr = Descriptor() + + exc = cm.exception + self.assertRegex(str(exc), r'\bNotGoingToWork\b') + self.assertRegex(str(exc), r'\battr\b') + self.assertRegex(str(exc), r'\bDescriptor\b') + self.assertIsInstance(exc.__cause__, TypeError) def test_set_name_lookup(self): resolved = [] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28214: Improved exception reporting for problematic __set_name__ + attributes. + - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7022,8 +7022,13 @@ if (set_name != NULL) { tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); Py_DECREF(set_name); - if (tmp == NULL) + if (tmp == NULL) { + _PyErr_FormatFromCause(PyExc_RuntimeError, + "Error calling __set_name__ on '%.100s' instance %R " + "in '%.100s'", + value->ob_type->tp_name, key, type->tp_name); return -1; + } else Py_DECREF(tmp); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 10:15:58 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 14:15:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328410=3A_Added_=5FPyErr=5FFormatFromCause=28=29?= =?utf-8?q?_--_the_helper_for_raising?= Message-ID: <20161021141540.9330.98036.E70E798A@psf.io> https://hg.python.org/cpython/rev/2119cb0beace changeset: 104609:2119cb0beace parent: 104607:e853492da42c parent: 104608:969c8bfe8872 user: Serhiy Storchaka date: Fri Oct 21 17:10:42 2016 +0300 summary: Issue #28410: Added _PyErr_FormatFromCause() -- the helper for raising new exception with setting current exception as __cause__. _PyErr_FormatFromCause(exception, format, args...) is equivalent to Python raise exception(format % args) from sys.exc_info()[1] files: Include/pyerrors.h | 11 +++++++ Lib/test/test_capi.py | 4 +- Modules/zipimport.c | 6 +-- Objects/abstract.c | 22 +++++++-------- Objects/genobject.c | 32 +--------------------- Objects/unicodeobject.c | 7 +--- Python/errors.c | 41 +++++++++++++++++++++++++++++ 7 files changed, 70 insertions(+), 53 deletions(-) diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -255,6 +255,17 @@ va_list vargs); #endif +#ifndef Py_LIMITED_API +/* Like PyErr_Format(), but saves current exception as __context__ and + __cause__. + */ +PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( + PyObject *exception, + const char *format, /* ASCII-encoded string */ + ... + ); +#endif + #ifdef MS_WINDOWS PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( int ierr, 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 @@ -222,8 +222,8 @@ br'result with an error set\n' br'ValueError\n' br'\n' - br'During handling of the above exception, ' - br'another exception occurred:\n' + br'The above exception was the direct cause ' + br'of the following exception:\n' br'\n' br'SystemError: ' diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -907,10 +907,8 @@ fp = _Py_fopen_obj(archive, "rb"); if (fp == NULL) { if (PyErr_ExceptionMatches(PyExc_OSError)) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - PyErr_Format(ZipImportError, "can't open Zip file: %R", archive); - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_FormatFromCause(ZipImportError, + "can't open Zip file: %R", archive); } return NULL; } diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2198,20 +2198,18 @@ } else { if (err_occurred) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - Py_DECREF(result); - if (func) - PyErr_Format(PyExc_SystemError, - "%R returned a result with an error set", - func); - else - PyErr_Format(PyExc_SystemError, - "%s returned a result with an error set", - where); - _PyErr_ChainExceptions(exc, val, tb); + if (func) { + _PyErr_FormatFromCause(PyExc_SystemError, + "%R returned a result with an error set", + func); + } + else { + _PyErr_FormatFromCause(PyExc_SystemError, + "%s returned a result with an error set", + where); + } #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode */ Py_FatalError("a function returned a result with an error set"); diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -118,33 +118,6 @@ PyObject_GC_Del(gen); } -static void -gen_chain_runtime_error(const char *msg) -{ - PyObject *exc, *val, *val2, *tb; - - /* TODO: This about rewriting using _PyErr_ChainExceptions. */ - - PyErr_Fetch(&exc, &val, &tb); - PyErr_NormalizeException(&exc, &val, &tb); - if (tb != NULL) { - PyException_SetTraceback(val, tb); - } - - Py_DECREF(exc); - Py_XDECREF(tb); - - PyErr_SetString(PyExc_RuntimeError, msg); - PyErr_Fetch(&exc, &val2, &tb); - PyErr_NormalizeException(&exc, &val2, &tb); - - Py_INCREF(val); - PyException_SetCause(val2, val); - PyException_SetContext(val2, val); - - PyErr_Restore(exc, val2, tb); -} - static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) { @@ -276,8 +249,7 @@ else if PyAsyncGen_CheckExact(gen) { msg = "async generator raised StopIteration"; } - /* Raise a RuntimeError */ - gen_chain_runtime_error(msg); + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } else { /* `gen` is an ordinary generator without @@ -309,7 +281,7 @@ raise a RuntimeError. */ const char *msg = "async generator raised StopAsyncIteration"; - gen_chain_runtime_error(msg); + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } if (!result || f->f_stacktop == NULL) { diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3831,13 +3831,10 @@ Py_FileSystemDefaultEncodeErrors); #ifdef MS_WINDOWS if (!res && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - PyErr_Format(PyExc_RuntimeError, - "filesystem path bytes were not correctly encoded with '%s'. " \ + _PyErr_FormatFromCause(PyExc_RuntimeError, + "filesystem path bytes were not correctly encoded with '%s'. " "Please report this at http://bugs.python.org/issue27781", Py_FileSystemDefaultEncoding); - _PyErr_ChainExceptions(exc, val, tb); } #endif return res; diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -401,6 +401,47 @@ } } +static PyObject * +_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs) +{ + PyObject *exc, *val, *val2, *tb; + + assert(PyErr_Occurred()); + PyErr_Fetch(&exc, &val, &tb); + PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } + Py_DECREF(exc); + assert(!PyErr_Occurred()); + + PyErr_FormatV(exception, format, vargs); + + PyErr_Fetch(&exc, &val2, &tb); + PyErr_NormalizeException(&exc, &val2, &tb); + Py_INCREF(val); + PyException_SetCause(val2, val); + PyException_SetContext(val2, val); + PyErr_Restore(exc, val2, tb); + + return NULL; +} + +PyObject * +_PyErr_FormatFromCause(PyObject *exception, const char *format, ...) +{ + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + _PyErr_FormatVFromCause(exception, format, vargs); + va_end(vargs); + return NULL; +} + /* Convenience functions to set a type error exception and return 0 */ int -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 10:15:58 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Oct 2016 14:15:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDEw?= =?utf-8?q?=3A_Added_=5FPyErr=5FFormatFromCause=28=29_--_the_helper_for_ra?= =?utf-8?q?ising?= Message-ID: <20161021141540.27160.49987.ED4A7439@psf.io> https://hg.python.org/cpython/rev/969c8bfe8872 changeset: 104608:969c8bfe8872 branch: 3.6 parent: 104606:23a1d9ec35d5 user: Serhiy Storchaka date: Fri Oct 21 17:09:17 2016 +0300 summary: Issue #28410: Added _PyErr_FormatFromCause() -- the helper for raising new exception with setting current exception as __cause__. _PyErr_FormatFromCause(exception, format, args...) is equivalent to Python raise exception(format % args) from sys.exc_info()[1] files: Include/pyerrors.h | 11 +++++++ Lib/test/test_capi.py | 4 +- Modules/zipimport.c | 6 +-- Objects/abstract.c | 22 +++++++-------- Objects/genobject.c | 32 +--------------------- Objects/unicodeobject.c | 7 +--- Python/errors.c | 41 +++++++++++++++++++++++++++++ 7 files changed, 70 insertions(+), 53 deletions(-) diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -255,6 +255,17 @@ va_list vargs); #endif +#ifndef Py_LIMITED_API +/* Like PyErr_Format(), but saves current exception as __context__ and + __cause__. + */ +PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( + PyObject *exception, + const char *format, /* ASCII-encoded string */ + ... + ); +#endif + #ifdef MS_WINDOWS PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( int ierr, 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 @@ -222,8 +222,8 @@ br'result with an error set\n' br'ValueError\n' br'\n' - br'During handling of the above exception, ' - br'another exception occurred:\n' + br'The above exception was the direct cause ' + br'of the following exception:\n' br'\n' br'SystemError: ' diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -907,10 +907,8 @@ fp = _Py_fopen_obj(archive, "rb"); if (fp == NULL) { if (PyErr_ExceptionMatches(PyExc_OSError)) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - PyErr_Format(ZipImportError, "can't open Zip file: %R", archive); - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_FormatFromCause(ZipImportError, + "can't open Zip file: %R", archive); } return NULL; } diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2198,20 +2198,18 @@ } else { if (err_occurred) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - Py_DECREF(result); - if (func) - PyErr_Format(PyExc_SystemError, - "%R returned a result with an error set", - func); - else - PyErr_Format(PyExc_SystemError, - "%s returned a result with an error set", - where); - _PyErr_ChainExceptions(exc, val, tb); + if (func) { + _PyErr_FormatFromCause(PyExc_SystemError, + "%R returned a result with an error set", + func); + } + else { + _PyErr_FormatFromCause(PyExc_SystemError, + "%s returned a result with an error set", + where); + } #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode */ Py_FatalError("a function returned a result with an error set"); diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -118,33 +118,6 @@ PyObject_GC_Del(gen); } -static void -gen_chain_runtime_error(const char *msg) -{ - PyObject *exc, *val, *val2, *tb; - - /* TODO: This about rewriting using _PyErr_ChainExceptions. */ - - PyErr_Fetch(&exc, &val, &tb); - PyErr_NormalizeException(&exc, &val, &tb); - if (tb != NULL) { - PyException_SetTraceback(val, tb); - } - - Py_DECREF(exc); - Py_XDECREF(tb); - - PyErr_SetString(PyExc_RuntimeError, msg); - PyErr_Fetch(&exc, &val2, &tb); - PyErr_NormalizeException(&exc, &val2, &tb); - - Py_INCREF(val); - PyException_SetCause(val2, val); - PyException_SetContext(val2, val); - - PyErr_Restore(exc, val2, tb); -} - static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) { @@ -276,8 +249,7 @@ else if PyAsyncGen_CheckExact(gen) { msg = "async generator raised StopIteration"; } - /* Raise a RuntimeError */ - gen_chain_runtime_error(msg); + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } else { /* `gen` is an ordinary generator without @@ -309,7 +281,7 @@ raise a RuntimeError. */ const char *msg = "async generator raised StopAsyncIteration"; - gen_chain_runtime_error(msg); + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } if (!result || f->f_stacktop == NULL) { diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3835,13 +3835,10 @@ Py_FileSystemDefaultEncodeErrors); #ifdef MS_WINDOWS if (!res && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - PyErr_Format(PyExc_RuntimeError, - "filesystem path bytes were not correctly encoded with '%s'. " \ + _PyErr_FormatFromCause(PyExc_RuntimeError, + "filesystem path bytes were not correctly encoded with '%s'. " "Please report this at http://bugs.python.org/issue27781", Py_FileSystemDefaultEncoding); - _PyErr_ChainExceptions(exc, val, tb); } #endif return res; diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -401,6 +401,47 @@ } } +static PyObject * +_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs) +{ + PyObject *exc, *val, *val2, *tb; + + assert(PyErr_Occurred()); + PyErr_Fetch(&exc, &val, &tb); + PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } + Py_DECREF(exc); + assert(!PyErr_Occurred()); + + PyErr_FormatV(exception, format, vargs); + + PyErr_Fetch(&exc, &val2, &tb); + PyErr_NormalizeException(&exc, &val2, &tb); + Py_INCREF(val); + PyException_SetCause(val2, val); + PyException_SetContext(val2, val); + PyErr_Restore(exc, val2, tb); + + return NULL; +} + +PyObject * +_PyErr_FormatFromCause(PyObject *exception, const char *format, ...) +{ + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + _PyErr_FormatVFromCause(exception, format, vargs); + va_end(vargs); + return NULL; +} + /* Convenience functions to set a type error exception and return 0 */ int -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 15:27:25 2016 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Oct 2016 19:27:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzk2?= =?utf-8?q?=3A_Remove_any_mention_of_=2Epyo_files_from_the_man_page=2E?= Message-ID: <20161021191621.16949.23677.DC6F43F0@psf.io> https://hg.python.org/cpython/rev/0c298486d879 changeset: 104612:0c298486d879 branch: 3.5 parent: 104605:81666d3e4a37 user: Brett Cannon date: Fri Oct 21 12:15:14 2016 -0700 summary: Issue #28396: Remove any mention of .pyo files from the man page. Thanks to Ville Skytt? for the patch. files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -111,7 +111,7 @@ .TP .B \-B Don't write -.I .py[co] +.I .pyc files on import. See also PYTHONDONTWRITEBYTECODE. .TP .B \-b @@ -391,7 +391,7 @@ .IP PYTHONDONTWRITEBYTECODE If this is set to a non-empty string it is equivalent to specifying the \fB\-B\fP option (don't try to write -.I .py[co] +.I .pyc files). .IP PYTHONINSPECT If this is set to a non-empty string it is equivalent to specifying -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 15:38:41 2016 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Oct 2016 19:38:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgKGlzc3VlICMyODM5Nik=?= Message-ID: <20161021191621.9377.82905.692AC934@psf.io> https://hg.python.org/cpython/rev/ef6c4e76f110 changeset: 104614:ef6c4e76f110 parent: 104611:7c3ec24f4582 parent: 104613:b33c7055220e user: Brett Cannon date: Fri Oct 21 12:16:14 2016 -0700 summary: Merge (issue #28396) files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -111,7 +111,7 @@ .TP .B \-B Don't write -.I .py[co] +.I .pyc files on import. See also PYTHONDONTWRITEBYTECODE. .TP .B \-b @@ -391,7 +391,7 @@ .IP PYTHONDONTWRITEBYTECODE If this is set to a non-empty string it is equivalent to specifying the \fB\-B\fP option (don't try to write -.I .py[co] +.I .pyc files). .IP PYTHONINSPECT If this is set to a non-empty string it is equivalent to specifying -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 15:38:41 2016 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Oct 2016 19:38:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_=28issue_=2328396=29?= Message-ID: <20161021191621.9426.68838.37A66A98@psf.io> https://hg.python.org/cpython/rev/b33c7055220e changeset: 104613:b33c7055220e branch: 3.6 parent: 104610:f7e1e39ccddd parent: 104612:0c298486d879 user: Brett Cannon date: Fri Oct 21 12:15:48 2016 -0700 summary: Merge (issue #28396) files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -111,7 +111,7 @@ .TP .B \-B Don't write -.I .py[co] +.I .pyc files on import. See also PYTHONDONTWRITEBYTECODE. .TP .B \-b @@ -391,7 +391,7 @@ .IP PYTHONDONTWRITEBYTECODE If this is set to a non-empty string it is equivalent to specifying the \fB\-B\fP option (don't try to write -.I .py[co] +.I .pyc files). .IP PYTHONINSPECT If this is set to a non-empty string it is equivalent to specifying -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 15:54:39 2016 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Oct 2016 19:54:39 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_=28issue_=2325152=29?= Message-ID: <20161021195438.68627.57078.36D0117D@psf.io> https://hg.python.org/cpython/rev/126ff1f3b6cd changeset: 104616:126ff1f3b6cd branch: 3.6 parent: 104613:b33c7055220e parent: 104615:9feff7ba89b2 user: Brett Cannon date: Fri Oct 21 12:54:02 2016 -0700 summary: Merge (issue #25152) files: Doc/library/venv.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -23,6 +23,12 @@ See :pep:`405` for more information about Python virtual environments. +.. note:: + The `pyvenv` script has been deprecated as of Python 3.6 in favor of using + ``python3 -m venv`` to help prevent any potential confusion as to which + Python interpreter a virtual environment will be based on. + + Creating virtual environments ----------------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 15:54:48 2016 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Oct 2016 19:54:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgKGlzc3VlICMyNTE1Mik=?= Message-ID: <20161021195438.12073.38880.02718BFE@psf.io> https://hg.python.org/cpython/rev/53bee4ef1d0a changeset: 104617:53bee4ef1d0a parent: 104614:ef6c4e76f110 parent: 104616:126ff1f3b6cd user: Brett Cannon date: Fri Oct 21 12:54:31 2016 -0700 summary: Merge (issue #25152) files: Doc/library/venv.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -23,6 +23,12 @@ See :pep:`405` for more information about Python virtual environments. +.. note:: + The `pyvenv` script has been deprecated as of Python 3.6 in favor of using + ``python3 -m venv`` to help prevent any potential confusion as to which + Python interpreter a virtual environment will be based on. + + Creating virtual environments ----------------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 15:54:48 2016 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Oct 2016 19:54:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI1MTUy?= =?utf-8?q?=3A_Mention_the_deprecation_of_pyvenv?= Message-ID: <20161021195438.25261.81499.993A9863@psf.io> https://hg.python.org/cpython/rev/9feff7ba89b2 changeset: 104615:9feff7ba89b2 branch: 3.5 parent: 104612:0c298486d879 user: Brett Cannon date: Fri Oct 21 12:53:40 2016 -0700 summary: Issue #25152: Mention the deprecation of pyvenv files: Doc/library/venv.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -23,6 +23,12 @@ See :pep:`405` for more information about Python virtual environments. +.. note:: + The `pyvenv` script has been deprecated as of Python 3.6 in favor of using + ``python3 -m venv`` to help prevent any potential confusion as to which + Python interpreter a virtual environment will be based on. + + Creating virtual environments ----------------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:14:23 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:14:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTAw?= =?utf-8?q?=3A_Fix_asyncio_to_handle_async_gens_GC_from_another_thread=2E?= Message-ID: <20161021211423.38835.23818.A49A4C43@psf.io> https://hg.python.org/cpython/rev/3908f432d0ac changeset: 104618:3908f432d0ac branch: 3.6 parent: 104616:126ff1f3b6cd user: Yury Selivanov date: Fri Oct 21 17:13:40 2016 -0400 summary: Issue #28500: Fix asyncio to handle async gens GC from another thread. files: Lib/asyncio/base_events.py | 3 +++ Misc/NEWS | 2 ++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -351,6 +351,9 @@ self._asyncgens.discard(agen) if not self.is_closed(): self.create_task(agen.aclose()) + # Wake up the loop if the finalizer was called from + # a different thread. + self._write_to_self() def _asyncgen_firstiter_hook(self, agen): if self._asyncgens_shutdown_called: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,8 @@ - Issue #28492: Fix how StopIteration exception is raised in _asyncio.Future. +- Issue #28500: Fix asyncio to handle async gens GC from another thread. + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:14:27 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:14:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg1MDAp?= Message-ID: <20161021211423.11909.28017.2AD1E89B@psf.io> https://hg.python.org/cpython/rev/3c82fa5b7b52 changeset: 104619:3c82fa5b7b52 parent: 104617:53bee4ef1d0a parent: 104618:3908f432d0ac user: Yury Selivanov date: Fri Oct 21 17:14:17 2016 -0400 summary: Merge 3.6 (issue #28500) files: Lib/asyncio/base_events.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -351,6 +351,9 @@ self._asyncgens.discard(agen) if not self.is_closed(): self.create_task(agen.aclose()) + # Wake up the loop if the finalizer was called from + # a different thread. + self._write_to_self() def _asyncgen_firstiter_hook(self, agen): if self._asyncgens_shutdown_called: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:25:10 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:25:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2OTIz?= =?utf-8?q?=3A_Fix_asyncio=2EGather_to_refuse_being_cancelled_once_all_chi?= =?utf-8?q?ldren?= Message-ID: <20161021212510.68411.81124.08A18ED4@psf.io> https://hg.python.org/cpython/rev/b1aa485fad1b changeset: 104620:b1aa485fad1b branch: 3.5 parent: 104615:9feff7ba89b2 user: Yury Selivanov date: Fri Oct 21 17:22:17 2016 -0400 summary: Issue #26923: Fix asyncio.Gather to refuse being cancelled once all children are done. Patch by Johannes Ebke. files: Lib/asyncio/tasks.py | 6 ++- Lib/test/test_asyncio/test_tasks.py | 30 +++++++++++++++++ Misc/NEWS | 4 ++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -592,9 +592,11 @@ def cancel(self): if self.done(): return False + ret = False for child in self._children: - child.cancel() - return True + if child.cancel(): + ret = True + return ret def gather(*coros_or_futures, loop=None, return_exceptions=False): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1899,6 +1899,36 @@ def test_cancel_wait_for(self): self._test_cancel_wait_for(60.0) + def test_cancel_gather(self): + """Ensure that a gathering future refuses to be cancelled once all + children are done""" + loop = asyncio.new_event_loop() + self.addCleanup(loop.close) + + fut = asyncio.Future(loop=loop) + # The indirection fut->child_coro is needed since otherwise the + # gathering task is done at the same time as the child future + def child_coro(): + return (yield from fut) + gather_future = asyncio.gather(child_coro(), loop=loop) + gather_task = asyncio.ensure_future(gather_future, loop=loop) + + cancel_result = None + def cancelling_callback(_): + nonlocal cancel_result + cancel_result = gather_task.cancel() + fut.add_done_callback(cancelling_callback) + + fut.set_result(42) # calls the cancelling_callback after fut is done() + + # At this point the task should complete. + loop.run_until_complete(gather_task) + + # Python issue #26923: asyncio.gather drops cancellation + self.assertEqual(cancel_result, False) + self.assertFalse(gather_task.cancelled()) + self.assertEqual(gather_task.result(), [42]) + class GatherTestsBase: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -398,6 +398,10 @@ - Issue #27972: Prohibit Tasks to await on themselves. +- Issue #26923: Fix asyncio.Gather to refuse being cancelled once all + children are done. + Patch by Johannes Ebke. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:25:10 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:25:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2326923=29?= Message-ID: <20161021212510.68647.22313.677749DA@psf.io> https://hg.python.org/cpython/rev/b0af901b1e2a changeset: 104621:b0af901b1e2a branch: 3.6 parent: 104618:3908f432d0ac parent: 104620:b1aa485fad1b user: Yury Selivanov date: Fri Oct 21 17:23:35 2016 -0400 summary: Merge 3.5 (issue #26923) files: Lib/asyncio/tasks.py | 6 ++- Lib/test/test_asyncio/test_tasks.py | 30 +++++++++++++++++ Misc/NEWS | 4 ++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -592,9 +592,11 @@ def cancel(self): if self.done(): return False + ret = False for child in self._children: - child.cancel() - return True + if child.cancel(): + ret = True + return ret def gather(*coros_or_futures, loop=None, return_exceptions=False): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1899,6 +1899,36 @@ def test_cancel_wait_for(self): self._test_cancel_wait_for(60.0) + def test_cancel_gather(self): + """Ensure that a gathering future refuses to be cancelled once all + children are done""" + loop = asyncio.new_event_loop() + self.addCleanup(loop.close) + + fut = asyncio.Future(loop=loop) + # The indirection fut->child_coro is needed since otherwise the + # gathering task is done at the same time as the child future + def child_coro(): + return (yield from fut) + gather_future = asyncio.gather(child_coro(), loop=loop) + gather_task = asyncio.ensure_future(gather_future, loop=loop) + + cancel_result = None + def cancelling_callback(_): + nonlocal cancel_result + cancel_result = gather_task.cancel() + fut.add_done_callback(cancelling_callback) + + fut.set_result(42) # calls the cancelling_callback after fut is done() + + # At this point the task should complete. + loop.run_until_complete(gather_task) + + # Python issue #26923: asyncio.gather drops cancellation + self.assertEqual(cancel_result, False) + self.assertFalse(gather_task.cancelled()) + self.assertEqual(gather_task.result(), [42]) + class GatherTestsBase: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -40,6 +40,10 @@ - Issue #28500: Fix asyncio to handle async gens GC from another thread. +- Issue #26923: Fix asyncio.Gather to refuse being cancelled once all + children are done. + Patch by Johannes Ebke. + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:25:11 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:25:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjY5MjMp?= Message-ID: <20161021212511.32698.62449.A6C47C7C@psf.io> https://hg.python.org/cpython/rev/2a228b03ea16 changeset: 104622:2a228b03ea16 parent: 104619:3c82fa5b7b52 parent: 104621:b0af901b1e2a user: Yury Selivanov date: Fri Oct 21 17:25:02 2016 -0400 summary: Merge 3.6 (issue #26923) files: Lib/asyncio/tasks.py | 6 ++- Lib/test/test_asyncio/test_tasks.py | 30 +++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -592,9 +592,11 @@ def cancel(self): if self.done(): return False + ret = False for child in self._children: - child.cancel() - return True + if child.cancel(): + ret = True + return ret def gather(*coros_or_futures, loop=None, return_exceptions=False): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1899,6 +1899,36 @@ def test_cancel_wait_for(self): self._test_cancel_wait_for(60.0) + def test_cancel_gather(self): + """Ensure that a gathering future refuses to be cancelled once all + children are done""" + loop = asyncio.new_event_loop() + self.addCleanup(loop.close) + + fut = asyncio.Future(loop=loop) + # The indirection fut->child_coro is needed since otherwise the + # gathering task is done at the same time as the child future + def child_coro(): + return (yield from fut) + gather_future = asyncio.gather(child_coro(), loop=loop) + gather_task = asyncio.ensure_future(gather_future, loop=loop) + + cancel_result = None + def cancelling_callback(_): + nonlocal cancel_result + cancel_result = gather_task.cancel() + fut.add_done_callback(cancelling_callback) + + fut.set_result(42) # calls the cancelling_callback after fut is done() + + # At this point the task should complete. + loop.run_until_complete(gather_task) + + # Python issue #26923: asyncio.gather drops cancellation + self.assertEqual(cancel_result, False) + self.assertFalse(gather_task.cancelled()) + self.assertEqual(gather_task.result(), [42]) + class GatherTestsBase: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:32:05 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 21:32:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fix_indent?= Message-ID: <20161021213155.11909.17421.5D17FBC2@psf.io> https://hg.python.org/cpython/rev/0b5e28042355 changeset: 104626:0b5e28042355 branch: 3.5 parent: 104623:fb03d179f824 user: Guido van Rossum date: Fri Oct 21 14:30:50 2016 -0700 summary: Fix indent files: Lib/typing.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -893,9 +893,9 @@ if hasattr(arg, '_subs_repr'): return arg._subs_repr(tvars, args) if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg.__name__ == tvar.__name__: - return args[i] + for i, tvar in enumerate(tvars): + if arg.__name__ == tvar.__name__: + return args[i] return _type_repr(arg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:32:05 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 21:32:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogRml4IGluZGVudCAobWVyZ2Up?= Message-ID: <20161021213155.9309.81682.8EC95F29@psf.io> https://hg.python.org/cpython/rev/f1a154e59323 changeset: 104628:f1a154e59323 parent: 104625:ac4082ef109e parent: 104627:60a57f15fb86 user: Guido van Rossum date: Fri Oct 21 14:31:37 2016 -0700 summary: Fix indent (merge) files: Lib/typing.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -893,9 +893,9 @@ if hasattr(arg, '_subs_repr'): return arg._subs_repr(tvars, args) if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg.__name__ == tvar.__name__: - return args[i] + for i, tvar in enumerate(tvars): + if arg.__name__ == tvar.__name__: + return args[i] return _type_repr(arg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:32:05 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 21:32:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Fix_indent_=28merge=29?= Message-ID: <20161021213155.25092.68680.411CF1AD@psf.io> https://hg.python.org/cpython/rev/60a57f15fb86 changeset: 104627:60a57f15fb86 branch: 3.6 parent: 104624:7bd7e4018199 parent: 104626:0b5e28042355 user: Guido van Rossum date: Fri Oct 21 14:31:18 2016 -0700 summary: Fix indent (merge) files: Lib/typing.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -893,9 +893,9 @@ if hasattr(arg, '_subs_repr'): return arg._subs_repr(tvars, args) if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg.__name__ == tvar.__name__: - return args[i] + for i, tvar in enumerate(tvars): + if arg.__name__ == tvar.__name__: + return args[i] return _type_repr(arg) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:32:05 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 21:32:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Sync_typing=2Epy_from_upstream_=283=2E5-=3E3=2E6=29?= Message-ID: <20161021213154.9814.65728.E4A2860A@psf.io> https://hg.python.org/cpython/rev/7bd7e4018199 changeset: 104624:7bd7e4018199 branch: 3.6 parent: 104621:b0af901b1e2a parent: 104623:fb03d179f824 user: Guido van Rossum date: Fri Oct 21 14:28:29 2016 -0700 summary: Sync typing.py from upstream (3.5->3.6) files: Lib/test/test_typing.py | 96 +++++++++++++++++++++++- Lib/typing.py | 107 ++++++++++++++++++++------- 2 files changed, 170 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -548,9 +548,9 @@ def test_repr(self): self.assertEqual(repr(SimpleMapping), - __name__ + '.' + 'SimpleMapping<~XK, ~XV>') + __name__ + '.' + 'SimpleMapping') self.assertEqual(repr(MySimpleMapping), - __name__ + '.' + 'MySimpleMapping<~XK, ~XV>') + __name__ + '.' + 'MySimpleMapping') def test_chain_repr(self): T = TypeVar('T') @@ -574,7 +574,36 @@ self.assertNotEqual(Z, Y[T]) self.assertTrue(str(Z).endswith( - '.C<~T>[typing.Tuple[~S, ~T]]<~S, ~T>[~T, int]<~T>[str]')) + '.C[typing.Tuple[str, int]]')) + + def test_new_repr(self): + T = TypeVar('T') + U = TypeVar('U', covariant=True) + S = TypeVar('S') + + self.assertEqual(repr(List), 'typing.List') + self.assertEqual(repr(List[T]), 'typing.List[~T]') + self.assertEqual(repr(List[U]), 'typing.List[+U]') + self.assertEqual(repr(List[S][T][int]), 'typing.List[int]') + self.assertEqual(repr(List[int]), 'typing.List[int]') + + def test_new_repr_complex(self): + T = TypeVar('T') + TS = TypeVar('TS') + + self.assertEqual(repr(typing.Mapping[T, TS][TS, T]), 'typing.Mapping[~TS, ~T]') + self.assertEqual(repr(List[Tuple[T, TS]][int, T]), + 'typing.List[typing.Tuple[int, ~T]]') + self.assertEqual(repr(List[Tuple[T, T]][List[int]]), + 'typing.List[typing.Tuple[typing.List[int], typing.List[int]]]') + + def test_new_repr_bare(self): + T = TypeVar('T') + self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]') + self.assertEqual(repr(typing._Protocol[T]), 'typing.Protocol[~T]') + class C(typing.Dict[Any, Any]): ... + # this line should just work + repr(C.__mro__) def test_dict(self): T = TypeVar('T') @@ -625,6 +654,63 @@ class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): pass + def test_orig_bases(self): + T = TypeVar('T') + class C(typing.Dict[str, T]): ... + self.assertEqual(C.__orig_bases__, (typing.Dict[str, T],)) + + def test_naive_runtime_checks(self): + def naive_dict_check(obj, tp): + # Check if a dictionary conforms to Dict type + if len(tp.__parameters__) > 0: + raise NotImplementedError + if tp.__args__: + KT, VT = tp.__args__ + return all(isinstance(k, KT) and isinstance(v, VT) + for k, v in obj.items()) + self.assertTrue(naive_dict_check({'x': 1}, typing.Dict[str, int])) + self.assertFalse(naive_dict_check({1: 'x'}, typing.Dict[str, int])) + with self.assertRaises(NotImplementedError): + naive_dict_check({1: 'x'}, typing.Dict[str, T]) + + def naive_generic_check(obj, tp): + # Check if an instance conforms to the generic class + if not hasattr(obj, '__orig_class__'): + raise NotImplementedError + return obj.__orig_class__ == tp + class Node(Generic[T]): ... + self.assertTrue(naive_generic_check(Node[int](), Node[int])) + self.assertFalse(naive_generic_check(Node[str](), Node[int])) + self.assertFalse(naive_generic_check(Node[str](), List)) + with self.assertRaises(NotImplementedError): + naive_generic_check([1,2,3], Node[int]) + + def naive_list_base_check(obj, tp): + # Check if list conforms to a List subclass + return all(isinstance(x, tp.__orig_bases__[0].__args__[0]) + for x in obj) + class C(List[int]): ... + self.assertTrue(naive_list_base_check([1, 2, 3], C)) + self.assertFalse(naive_list_base_check(['a', 'b'], C)) + + def test_multi_subscr_base(self): + T = TypeVar('T') + U = TypeVar('U') + V = TypeVar('V') + class C(List[T][U][V]): ... + class D(C, List[T][U][V]): ... + self.assertEqual(C.__parameters__, (V,)) + self.assertEqual(D.__parameters__, (V,)) + self.assertEqual(C[int].__parameters__, ()) + self.assertEqual(D[int].__parameters__, ()) + self.assertEqual(C[int].__args__, (int,)) + self.assertEqual(D[int].__args__, (int,)) + self.assertEqual(C.__bases__, (List,)) + self.assertEqual(D.__bases__, (C, List)) + self.assertEqual(C.__orig_bases__, (List[T][U][V],)) + self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) + + def test_pickle(self): global C # pickle wants to reference the class by name T = TypeVar('T') @@ -662,12 +748,12 @@ if not PY32: self.assertEqual(C.__qualname__, 'GenericTests.test_repr_2..C') - self.assertEqual(repr(C).split('.')[-1], 'C<~T>') + self.assertEqual(repr(C).split('.')[-1], 'C') X = C[int] self.assertEqual(X.__module__, __name__) if not PY32: self.assertEqual(X.__qualname__, 'C') - self.assertEqual(repr(X).split('.')[-1], 'C<~T>[int]') + self.assertEqual(repr(X).split('.')[-1], 'C[int]') class Y(C[int]): pass diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -292,8 +292,8 @@ if not issubclass(parameter, self.type_var.__constraints__): raise TypeError("%s is not a valid substitution for %s." % (parameter, self.type_var)) - if isinstance(parameter, TypeVar): - raise TypeError("%s cannot be re-parameterized." % self.type_var) + if isinstance(parameter, TypeVar) and parameter is not self.type_var: + raise TypeError("%s cannot be re-parameterized." % self) return self.__class__(self.name, parameter, self.impl_type, self.type_checker) @@ -622,9 +622,12 @@ _get_type_vars(self.__union_params__, tvars) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__union_params__: - r += '[%s]' % (', '.join(_type_repr(t) + r += '[%s]' % (', '.join(_replace_arg(t, tvars, args) for t in self.__union_params__)) return r @@ -706,9 +709,12 @@ return self.__class__(p, _root=True) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__tuple_params__ is not None: - params = [_type_repr(p) for p in self.__tuple_params__] + params = [_replace_arg(p, tvars, args) for p in self.__tuple_params__] if self.__tuple_use_ellipsis__: params.append('...') if not params: @@ -791,6 +797,8 @@ def _get_type_vars(self, tvars): if self.__args__ and self.__args__ is not Ellipsis: _get_type_vars(self.__args__, tvars) + if self.__result__: + _get_type_vars([self.__result__], tvars) def _eval_type(self, globalns, localns): if self.__args__ is None and self.__result__ is None: @@ -806,14 +814,17 @@ return self.__class__(args, result, _root=True) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__args__ is not None or self.__result__ is not None: if self.__args__ is Ellipsis: args_r = '...' else: - args_r = '[%s]' % ', '.join(_type_repr(t) + args_r = '[%s]' % ', '.join(_replace_arg(t, tvars, args) for t in self.__args__) - r += '[%s, %s]' % (args_r, _type_repr(self.__result__)) + r += '[%s, %s]' % (args_r, _replace_arg(self.__result__, tvars, args)) return r def __getitem__(self, parameters): @@ -878,6 +889,16 @@ return _gorg(a) is _gorg(b) +def _replace_arg(arg, tvars, args): + if hasattr(arg, '_subs_repr'): + return arg._subs_repr(tvars, args) + if isinstance(arg, TypeVar): + for i, tvar in enumerate(tvars): + if arg.__name__ == tvar.__name__: + return args[i] + return _type_repr(arg) + + def _next_in_mro(cls): """Helper for Generic.__new__. @@ -938,11 +959,7 @@ """Metaclass for generic types.""" def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None): - if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: - bases = (extra,) + bases - self = super().__new__(cls, name, bases, namespace, _root=True) - + tvars=None, args=None, origin=None, extra=None, orig_bases=None): if tvars is not None: # Called from __getitem__() below. assert origin is not None @@ -983,12 +1000,25 @@ ", ".join(str(g) for g in gvars))) tvars = gvars + initial_bases = bases + if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: + bases = (extra,) + bases + bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b for b in bases) + + # remove bare Generic from bases if there are other generic bases + if any(isinstance(b, GenericMeta) and b is not Generic for b in bases): + bases = tuple(b for b in bases if b is not Generic) + self = super().__new__(cls, name, bases, namespace, _root=True) + self.__parameters__ = tvars self.__args__ = args self.__origin__ = origin self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). self.__next_in_mro__ = _next_in_mro(self) + # Preserve base classes on subclassing (__bases__ are type erased now). + if orig_bases is None: + self.__orig_bases__ = initial_bases # This allows unparameterized generic collections to be used # with issubclass() and isinstance() in the same way as their @@ -1006,17 +1036,29 @@ _get_type_vars(self.__parameters__, tvars) def __repr__(self): - if self.__origin__ is not None: - r = repr(self.__origin__) - else: - r = super().__repr__() - if self.__args__: - r += '[%s]' % ( - ', '.join(_type_repr(p) for p in self.__args__)) - if self.__parameters__: - r += '<%s>' % ( - ', '.join(_type_repr(p) for p in self.__parameters__)) - return r + if self.__origin__ is None: + return super().__repr__() + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): + assert len(tvars) == len(args) + # Construct the chain of __origin__'s. + current = self.__origin__ + orig_chain = [] + while current.__origin__ is not None: + orig_chain.append(current) + current = current.__origin__ + # Replace type variables in __args__ if asked ... + str_args = [] + for arg in self.__args__: + str_args.append(_replace_arg(arg, tvars, args)) + # ... then continue replacing down the origin chain. + for cls in orig_chain: + new_str_args = [] + for i, arg in enumerate(cls.__args__): + new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args)) + str_args = new_str_args + return super().__repr__() + '[%s]' % ', '.join(str_args) def __eq__(self, other): if not isinstance(other, GenericMeta): @@ -1049,11 +1091,11 @@ raise TypeError( "Parameters to Generic[...] must all be unique") tvars = params - args = None + args = params elif self is _Protocol: # _Protocol is internal, don't check anything. tvars = params - args = None + args = params elif self.__origin__ in (Generic, _Protocol): # Can't subscript Generic[...] or _Protocol[...]. raise TypeError("Cannot subscript already-subscripted %s" % @@ -1071,12 +1113,13 @@ tvars = _type_vars(params) args = params return self.__class__(self.__name__, - (self,) + self.__bases__, + self.__bases__, dict(self.__dict__), tvars=tvars, args=args, origin=self, - extra=self.__extra__) + extra=self.__extra__, + orig_bases=self.__orig_bases__) def __instancecheck__(self, instance): # Since we extend ABC.__subclasscheck__ and @@ -1120,6 +1163,10 @@ else: origin = _gorg(cls) obj = cls.__next_in_mro__.__new__(origin) + try: + obj.__orig_class__ = cls + except AttributeError: + pass obj.__init__(*args, **kwds) return obj @@ -1163,12 +1210,15 @@ def _get_type_vars(self, tvars): if self.__type__: - _get_type_vars(self.__type__, tvars) + _get_type_vars([self.__type__], tvars) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(_type_repr(self.__type__)) + r += '[{}]'.format(_replace_arg(self.__type__, tvars, args)) return r def __hash__(self): @@ -1485,6 +1535,7 @@ attr != '__next_in_mro__' and attr != '__parameters__' and attr != '__origin__' and + attr != '__orig_bases__' and attr != '__extra__' and attr != '__module__'): attrs.add(attr) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:32:05 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 21:32:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogU3luYyB0eXBpbmcu?= =?utf-8?q?py_from_upstream?= Message-ID: <20161021213154.12283.54760.82D45570@psf.io> https://hg.python.org/cpython/rev/fb03d179f824 changeset: 104623:fb03d179f824 branch: 3.5 parent: 104620:b1aa485fad1b user: Guido van Rossum date: Fri Oct 21 14:27:58 2016 -0700 summary: Sync typing.py from upstream files: Lib/test/test_typing.py | 96 +++++++++++++++++++++++- Lib/typing.py | 107 ++++++++++++++++++++------- 2 files changed, 170 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -548,9 +548,9 @@ def test_repr(self): self.assertEqual(repr(SimpleMapping), - __name__ + '.' + 'SimpleMapping<~XK, ~XV>') + __name__ + '.' + 'SimpleMapping') self.assertEqual(repr(MySimpleMapping), - __name__ + '.' + 'MySimpleMapping<~XK, ~XV>') + __name__ + '.' + 'MySimpleMapping') def test_chain_repr(self): T = TypeVar('T') @@ -574,7 +574,36 @@ self.assertNotEqual(Z, Y[T]) self.assertTrue(str(Z).endswith( - '.C<~T>[typing.Tuple[~S, ~T]]<~S, ~T>[~T, int]<~T>[str]')) + '.C[typing.Tuple[str, int]]')) + + def test_new_repr(self): + T = TypeVar('T') + U = TypeVar('U', covariant=True) + S = TypeVar('S') + + self.assertEqual(repr(List), 'typing.List') + self.assertEqual(repr(List[T]), 'typing.List[~T]') + self.assertEqual(repr(List[U]), 'typing.List[+U]') + self.assertEqual(repr(List[S][T][int]), 'typing.List[int]') + self.assertEqual(repr(List[int]), 'typing.List[int]') + + def test_new_repr_complex(self): + T = TypeVar('T') + TS = TypeVar('TS') + + self.assertEqual(repr(typing.Mapping[T, TS][TS, T]), 'typing.Mapping[~TS, ~T]') + self.assertEqual(repr(List[Tuple[T, TS]][int, T]), + 'typing.List[typing.Tuple[int, ~T]]') + self.assertEqual(repr(List[Tuple[T, T]][List[int]]), + 'typing.List[typing.Tuple[typing.List[int], typing.List[int]]]') + + def test_new_repr_bare(self): + T = TypeVar('T') + self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]') + self.assertEqual(repr(typing._Protocol[T]), 'typing.Protocol[~T]') + class C(typing.Dict[Any, Any]): ... + # this line should just work + repr(C.__mro__) def test_dict(self): T = TypeVar('T') @@ -625,6 +654,63 @@ class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): pass + def test_orig_bases(self): + T = TypeVar('T') + class C(typing.Dict[str, T]): ... + self.assertEqual(C.__orig_bases__, (typing.Dict[str, T],)) + + def test_naive_runtime_checks(self): + def naive_dict_check(obj, tp): + # Check if a dictionary conforms to Dict type + if len(tp.__parameters__) > 0: + raise NotImplementedError + if tp.__args__: + KT, VT = tp.__args__ + return all(isinstance(k, KT) and isinstance(v, VT) + for k, v in obj.items()) + self.assertTrue(naive_dict_check({'x': 1}, typing.Dict[str, int])) + self.assertFalse(naive_dict_check({1: 'x'}, typing.Dict[str, int])) + with self.assertRaises(NotImplementedError): + naive_dict_check({1: 'x'}, typing.Dict[str, T]) + + def naive_generic_check(obj, tp): + # Check if an instance conforms to the generic class + if not hasattr(obj, '__orig_class__'): + raise NotImplementedError + return obj.__orig_class__ == tp + class Node(Generic[T]): ... + self.assertTrue(naive_generic_check(Node[int](), Node[int])) + self.assertFalse(naive_generic_check(Node[str](), Node[int])) + self.assertFalse(naive_generic_check(Node[str](), List)) + with self.assertRaises(NotImplementedError): + naive_generic_check([1,2,3], Node[int]) + + def naive_list_base_check(obj, tp): + # Check if list conforms to a List subclass + return all(isinstance(x, tp.__orig_bases__[0].__args__[0]) + for x in obj) + class C(List[int]): ... + self.assertTrue(naive_list_base_check([1, 2, 3], C)) + self.assertFalse(naive_list_base_check(['a', 'b'], C)) + + def test_multi_subscr_base(self): + T = TypeVar('T') + U = TypeVar('U') + V = TypeVar('V') + class C(List[T][U][V]): ... + class D(C, List[T][U][V]): ... + self.assertEqual(C.__parameters__, (V,)) + self.assertEqual(D.__parameters__, (V,)) + self.assertEqual(C[int].__parameters__, ()) + self.assertEqual(D[int].__parameters__, ()) + self.assertEqual(C[int].__args__, (int,)) + self.assertEqual(D[int].__args__, (int,)) + self.assertEqual(C.__bases__, (List,)) + self.assertEqual(D.__bases__, (C, List)) + self.assertEqual(C.__orig_bases__, (List[T][U][V],)) + self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) + + def test_pickle(self): global C # pickle wants to reference the class by name T = TypeVar('T') @@ -662,12 +748,12 @@ if not PY32: self.assertEqual(C.__qualname__, 'GenericTests.test_repr_2..C') - self.assertEqual(repr(C).split('.')[-1], 'C<~T>') + self.assertEqual(repr(C).split('.')[-1], 'C') X = C[int] self.assertEqual(X.__module__, __name__) if not PY32: self.assertEqual(X.__qualname__, 'C') - self.assertEqual(repr(X).split('.')[-1], 'C<~T>[int]') + self.assertEqual(repr(X).split('.')[-1], 'C[int]') class Y(C[int]): pass diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -292,8 +292,8 @@ if not issubclass(parameter, self.type_var.__constraints__): raise TypeError("%s is not a valid substitution for %s." % (parameter, self.type_var)) - if isinstance(parameter, TypeVar): - raise TypeError("%s cannot be re-parameterized." % self.type_var) + if isinstance(parameter, TypeVar) and parameter is not self.type_var: + raise TypeError("%s cannot be re-parameterized." % self) return self.__class__(self.name, parameter, self.impl_type, self.type_checker) @@ -622,9 +622,12 @@ _get_type_vars(self.__union_params__, tvars) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__union_params__: - r += '[%s]' % (', '.join(_type_repr(t) + r += '[%s]' % (', '.join(_replace_arg(t, tvars, args) for t in self.__union_params__)) return r @@ -706,9 +709,12 @@ return self.__class__(p, _root=True) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__tuple_params__ is not None: - params = [_type_repr(p) for p in self.__tuple_params__] + params = [_replace_arg(p, tvars, args) for p in self.__tuple_params__] if self.__tuple_use_ellipsis__: params.append('...') if not params: @@ -791,6 +797,8 @@ def _get_type_vars(self, tvars): if self.__args__ and self.__args__ is not Ellipsis: _get_type_vars(self.__args__, tvars) + if self.__result__: + _get_type_vars([self.__result__], tvars) def _eval_type(self, globalns, localns): if self.__args__ is None and self.__result__ is None: @@ -806,14 +814,17 @@ return self.__class__(args, result, _root=True) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__args__ is not None or self.__result__ is not None: if self.__args__ is Ellipsis: args_r = '...' else: - args_r = '[%s]' % ', '.join(_type_repr(t) + args_r = '[%s]' % ', '.join(_replace_arg(t, tvars, args) for t in self.__args__) - r += '[%s, %s]' % (args_r, _type_repr(self.__result__)) + r += '[%s, %s]' % (args_r, _replace_arg(self.__result__, tvars, args)) return r def __getitem__(self, parameters): @@ -878,6 +889,16 @@ return _gorg(a) is _gorg(b) +def _replace_arg(arg, tvars, args): + if hasattr(arg, '_subs_repr'): + return arg._subs_repr(tvars, args) + if isinstance(arg, TypeVar): + for i, tvar in enumerate(tvars): + if arg.__name__ == tvar.__name__: + return args[i] + return _type_repr(arg) + + def _next_in_mro(cls): """Helper for Generic.__new__. @@ -938,11 +959,7 @@ """Metaclass for generic types.""" def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None): - if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: - bases = (extra,) + bases - self = super().__new__(cls, name, bases, namespace, _root=True) - + tvars=None, args=None, origin=None, extra=None, orig_bases=None): if tvars is not None: # Called from __getitem__() below. assert origin is not None @@ -983,12 +1000,25 @@ ", ".join(str(g) for g in gvars))) tvars = gvars + initial_bases = bases + if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: + bases = (extra,) + bases + bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b for b in bases) + + # remove bare Generic from bases if there are other generic bases + if any(isinstance(b, GenericMeta) and b is not Generic for b in bases): + bases = tuple(b for b in bases if b is not Generic) + self = super().__new__(cls, name, bases, namespace, _root=True) + self.__parameters__ = tvars self.__args__ = args self.__origin__ = origin self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). self.__next_in_mro__ = _next_in_mro(self) + # Preserve base classes on subclassing (__bases__ are type erased now). + if orig_bases is None: + self.__orig_bases__ = initial_bases # This allows unparameterized generic collections to be used # with issubclass() and isinstance() in the same way as their @@ -1006,17 +1036,29 @@ _get_type_vars(self.__parameters__, tvars) def __repr__(self): - if self.__origin__ is not None: - r = repr(self.__origin__) - else: - r = super().__repr__() - if self.__args__: - r += '[%s]' % ( - ', '.join(_type_repr(p) for p in self.__args__)) - if self.__parameters__: - r += '<%s>' % ( - ', '.join(_type_repr(p) for p in self.__parameters__)) - return r + if self.__origin__ is None: + return super().__repr__() + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): + assert len(tvars) == len(args) + # Construct the chain of __origin__'s. + current = self.__origin__ + orig_chain = [] + while current.__origin__ is not None: + orig_chain.append(current) + current = current.__origin__ + # Replace type variables in __args__ if asked ... + str_args = [] + for arg in self.__args__: + str_args.append(_replace_arg(arg, tvars, args)) + # ... then continue replacing down the origin chain. + for cls in orig_chain: + new_str_args = [] + for i, arg in enumerate(cls.__args__): + new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args)) + str_args = new_str_args + return super().__repr__() + '[%s]' % ', '.join(str_args) def __eq__(self, other): if not isinstance(other, GenericMeta): @@ -1049,11 +1091,11 @@ raise TypeError( "Parameters to Generic[...] must all be unique") tvars = params - args = None + args = params elif self is _Protocol: # _Protocol is internal, don't check anything. tvars = params - args = None + args = params elif self.__origin__ in (Generic, _Protocol): # Can't subscript Generic[...] or _Protocol[...]. raise TypeError("Cannot subscript already-subscripted %s" % @@ -1071,12 +1113,13 @@ tvars = _type_vars(params) args = params return self.__class__(self.__name__, - (self,) + self.__bases__, + self.__bases__, dict(self.__dict__), tvars=tvars, args=args, origin=self, - extra=self.__extra__) + extra=self.__extra__, + orig_bases=self.__orig_bases__) def __instancecheck__(self, instance): # Since we extend ABC.__subclasscheck__ and @@ -1120,6 +1163,10 @@ else: origin = _gorg(cls) obj = cls.__next_in_mro__.__new__(origin) + try: + obj.__orig_class__ = cls + except AttributeError: + pass obj.__init__(*args, **kwds) return obj @@ -1163,12 +1210,15 @@ def _get_type_vars(self, tvars): if self.__type__: - _get_type_vars(self.__type__, tvars) + _get_type_vars([self.__type__], tvars) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(_type_repr(self.__type__)) + r += '[{}]'.format(_replace_arg(self.__type__, tvars, args)) return r def __hash__(self): @@ -1485,6 +1535,7 @@ attr != '__next_in_mro__' and attr != '__parameters__' and attr != '__origin__' and + attr != '__orig_bases__' and attr != '__extra__' and attr != '__module__'): attrs.add(attr) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:32:05 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 21:32:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogU3luYyB0eXBpbmcucHkgZnJvbSB1cHN0cmVhbSAoMy42LT4zLjcp?= Message-ID: <20161021213154.18258.57399.D2CA9539@psf.io> https://hg.python.org/cpython/rev/ac4082ef109e changeset: 104625:ac4082ef109e parent: 104622:2a228b03ea16 parent: 104624:7bd7e4018199 user: Guido van Rossum date: Fri Oct 21 14:29:02 2016 -0700 summary: Sync typing.py from upstream (3.6->3.7) files: Lib/test/test_typing.py | 96 +++++++++++++++++++++++- Lib/typing.py | 107 ++++++++++++++++++++------- 2 files changed, 170 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -548,9 +548,9 @@ def test_repr(self): self.assertEqual(repr(SimpleMapping), - __name__ + '.' + 'SimpleMapping<~XK, ~XV>') + __name__ + '.' + 'SimpleMapping') self.assertEqual(repr(MySimpleMapping), - __name__ + '.' + 'MySimpleMapping<~XK, ~XV>') + __name__ + '.' + 'MySimpleMapping') def test_chain_repr(self): T = TypeVar('T') @@ -574,7 +574,36 @@ self.assertNotEqual(Z, Y[T]) self.assertTrue(str(Z).endswith( - '.C<~T>[typing.Tuple[~S, ~T]]<~S, ~T>[~T, int]<~T>[str]')) + '.C[typing.Tuple[str, int]]')) + + def test_new_repr(self): + T = TypeVar('T') + U = TypeVar('U', covariant=True) + S = TypeVar('S') + + self.assertEqual(repr(List), 'typing.List') + self.assertEqual(repr(List[T]), 'typing.List[~T]') + self.assertEqual(repr(List[U]), 'typing.List[+U]') + self.assertEqual(repr(List[S][T][int]), 'typing.List[int]') + self.assertEqual(repr(List[int]), 'typing.List[int]') + + def test_new_repr_complex(self): + T = TypeVar('T') + TS = TypeVar('TS') + + self.assertEqual(repr(typing.Mapping[T, TS][TS, T]), 'typing.Mapping[~TS, ~T]') + self.assertEqual(repr(List[Tuple[T, TS]][int, T]), + 'typing.List[typing.Tuple[int, ~T]]') + self.assertEqual(repr(List[Tuple[T, T]][List[int]]), + 'typing.List[typing.Tuple[typing.List[int], typing.List[int]]]') + + def test_new_repr_bare(self): + T = TypeVar('T') + self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]') + self.assertEqual(repr(typing._Protocol[T]), 'typing.Protocol[~T]') + class C(typing.Dict[Any, Any]): ... + # this line should just work + repr(C.__mro__) def test_dict(self): T = TypeVar('T') @@ -625,6 +654,63 @@ class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): pass + def test_orig_bases(self): + T = TypeVar('T') + class C(typing.Dict[str, T]): ... + self.assertEqual(C.__orig_bases__, (typing.Dict[str, T],)) + + def test_naive_runtime_checks(self): + def naive_dict_check(obj, tp): + # Check if a dictionary conforms to Dict type + if len(tp.__parameters__) > 0: + raise NotImplementedError + if tp.__args__: + KT, VT = tp.__args__ + return all(isinstance(k, KT) and isinstance(v, VT) + for k, v in obj.items()) + self.assertTrue(naive_dict_check({'x': 1}, typing.Dict[str, int])) + self.assertFalse(naive_dict_check({1: 'x'}, typing.Dict[str, int])) + with self.assertRaises(NotImplementedError): + naive_dict_check({1: 'x'}, typing.Dict[str, T]) + + def naive_generic_check(obj, tp): + # Check if an instance conforms to the generic class + if not hasattr(obj, '__orig_class__'): + raise NotImplementedError + return obj.__orig_class__ == tp + class Node(Generic[T]): ... + self.assertTrue(naive_generic_check(Node[int](), Node[int])) + self.assertFalse(naive_generic_check(Node[str](), Node[int])) + self.assertFalse(naive_generic_check(Node[str](), List)) + with self.assertRaises(NotImplementedError): + naive_generic_check([1,2,3], Node[int]) + + def naive_list_base_check(obj, tp): + # Check if list conforms to a List subclass + return all(isinstance(x, tp.__orig_bases__[0].__args__[0]) + for x in obj) + class C(List[int]): ... + self.assertTrue(naive_list_base_check([1, 2, 3], C)) + self.assertFalse(naive_list_base_check(['a', 'b'], C)) + + def test_multi_subscr_base(self): + T = TypeVar('T') + U = TypeVar('U') + V = TypeVar('V') + class C(List[T][U][V]): ... + class D(C, List[T][U][V]): ... + self.assertEqual(C.__parameters__, (V,)) + self.assertEqual(D.__parameters__, (V,)) + self.assertEqual(C[int].__parameters__, ()) + self.assertEqual(D[int].__parameters__, ()) + self.assertEqual(C[int].__args__, (int,)) + self.assertEqual(D[int].__args__, (int,)) + self.assertEqual(C.__bases__, (List,)) + self.assertEqual(D.__bases__, (C, List)) + self.assertEqual(C.__orig_bases__, (List[T][U][V],)) + self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) + + def test_pickle(self): global C # pickle wants to reference the class by name T = TypeVar('T') @@ -662,12 +748,12 @@ if not PY32: self.assertEqual(C.__qualname__, 'GenericTests.test_repr_2..C') - self.assertEqual(repr(C).split('.')[-1], 'C<~T>') + self.assertEqual(repr(C).split('.')[-1], 'C') X = C[int] self.assertEqual(X.__module__, __name__) if not PY32: self.assertEqual(X.__qualname__, 'C') - self.assertEqual(repr(X).split('.')[-1], 'C<~T>[int]') + self.assertEqual(repr(X).split('.')[-1], 'C[int]') class Y(C[int]): pass diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -292,8 +292,8 @@ if not issubclass(parameter, self.type_var.__constraints__): raise TypeError("%s is not a valid substitution for %s." % (parameter, self.type_var)) - if isinstance(parameter, TypeVar): - raise TypeError("%s cannot be re-parameterized." % self.type_var) + if isinstance(parameter, TypeVar) and parameter is not self.type_var: + raise TypeError("%s cannot be re-parameterized." % self) return self.__class__(self.name, parameter, self.impl_type, self.type_checker) @@ -622,9 +622,12 @@ _get_type_vars(self.__union_params__, tvars) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__union_params__: - r += '[%s]' % (', '.join(_type_repr(t) + r += '[%s]' % (', '.join(_replace_arg(t, tvars, args) for t in self.__union_params__)) return r @@ -706,9 +709,12 @@ return self.__class__(p, _root=True) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__tuple_params__ is not None: - params = [_type_repr(p) for p in self.__tuple_params__] + params = [_replace_arg(p, tvars, args) for p in self.__tuple_params__] if self.__tuple_use_ellipsis__: params.append('...') if not params: @@ -791,6 +797,8 @@ def _get_type_vars(self, tvars): if self.__args__ and self.__args__ is not Ellipsis: _get_type_vars(self.__args__, tvars) + if self.__result__: + _get_type_vars([self.__result__], tvars) def _eval_type(self, globalns, localns): if self.__args__ is None and self.__result__ is None: @@ -806,14 +814,17 @@ return self.__class__(args, result, _root=True) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__args__ is not None or self.__result__ is not None: if self.__args__ is Ellipsis: args_r = '...' else: - args_r = '[%s]' % ', '.join(_type_repr(t) + args_r = '[%s]' % ', '.join(_replace_arg(t, tvars, args) for t in self.__args__) - r += '[%s, %s]' % (args_r, _type_repr(self.__result__)) + r += '[%s, %s]' % (args_r, _replace_arg(self.__result__, tvars, args)) return r def __getitem__(self, parameters): @@ -878,6 +889,16 @@ return _gorg(a) is _gorg(b) +def _replace_arg(arg, tvars, args): + if hasattr(arg, '_subs_repr'): + return arg._subs_repr(tvars, args) + if isinstance(arg, TypeVar): + for i, tvar in enumerate(tvars): + if arg.__name__ == tvar.__name__: + return args[i] + return _type_repr(arg) + + def _next_in_mro(cls): """Helper for Generic.__new__. @@ -938,11 +959,7 @@ """Metaclass for generic types.""" def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None): - if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: - bases = (extra,) + bases - self = super().__new__(cls, name, bases, namespace, _root=True) - + tvars=None, args=None, origin=None, extra=None, orig_bases=None): if tvars is not None: # Called from __getitem__() below. assert origin is not None @@ -983,12 +1000,25 @@ ", ".join(str(g) for g in gvars))) tvars = gvars + initial_bases = bases + if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: + bases = (extra,) + bases + bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b for b in bases) + + # remove bare Generic from bases if there are other generic bases + if any(isinstance(b, GenericMeta) and b is not Generic for b in bases): + bases = tuple(b for b in bases if b is not Generic) + self = super().__new__(cls, name, bases, namespace, _root=True) + self.__parameters__ = tvars self.__args__ = args self.__origin__ = origin self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). self.__next_in_mro__ = _next_in_mro(self) + # Preserve base classes on subclassing (__bases__ are type erased now). + if orig_bases is None: + self.__orig_bases__ = initial_bases # This allows unparameterized generic collections to be used # with issubclass() and isinstance() in the same way as their @@ -1006,17 +1036,29 @@ _get_type_vars(self.__parameters__, tvars) def __repr__(self): - if self.__origin__ is not None: - r = repr(self.__origin__) - else: - r = super().__repr__() - if self.__args__: - r += '[%s]' % ( - ', '.join(_type_repr(p) for p in self.__args__)) - if self.__parameters__: - r += '<%s>' % ( - ', '.join(_type_repr(p) for p in self.__parameters__)) - return r + if self.__origin__ is None: + return super().__repr__() + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): + assert len(tvars) == len(args) + # Construct the chain of __origin__'s. + current = self.__origin__ + orig_chain = [] + while current.__origin__ is not None: + orig_chain.append(current) + current = current.__origin__ + # Replace type variables in __args__ if asked ... + str_args = [] + for arg in self.__args__: + str_args.append(_replace_arg(arg, tvars, args)) + # ... then continue replacing down the origin chain. + for cls in orig_chain: + new_str_args = [] + for i, arg in enumerate(cls.__args__): + new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args)) + str_args = new_str_args + return super().__repr__() + '[%s]' % ', '.join(str_args) def __eq__(self, other): if not isinstance(other, GenericMeta): @@ -1049,11 +1091,11 @@ raise TypeError( "Parameters to Generic[...] must all be unique") tvars = params - args = None + args = params elif self is _Protocol: # _Protocol is internal, don't check anything. tvars = params - args = None + args = params elif self.__origin__ in (Generic, _Protocol): # Can't subscript Generic[...] or _Protocol[...]. raise TypeError("Cannot subscript already-subscripted %s" % @@ -1071,12 +1113,13 @@ tvars = _type_vars(params) args = params return self.__class__(self.__name__, - (self,) + self.__bases__, + self.__bases__, dict(self.__dict__), tvars=tvars, args=args, origin=self, - extra=self.__extra__) + extra=self.__extra__, + orig_bases=self.__orig_bases__) def __instancecheck__(self, instance): # Since we extend ABC.__subclasscheck__ and @@ -1120,6 +1163,10 @@ else: origin = _gorg(cls) obj = cls.__next_in_mro__.__new__(origin) + try: + obj.__orig_class__ = cls + except AttributeError: + pass obj.__init__(*args, **kwds) return obj @@ -1163,12 +1210,15 @@ def _get_type_vars(self, tvars): if self.__type__: - _get_type_vars(self.__type__, tvars) + _get_type_vars([self.__type__], tvars) def __repr__(self): + return self._subs_repr([], []) + + def _subs_repr(self, tvars, args): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(_type_repr(self.__type__)) + r += '[{}]'.format(_replace_arg(self.__type__, tvars, args)) return r def __hash__(self): @@ -1485,6 +1535,7 @@ attr != '__next_in_mro__' and attr != '__parameters__' and attr != '__origin__' and + attr != '__orig_bases__' and attr != '__extra__' and attr != '__module__'): attrs.add(attr) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:42:05 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:42:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_3=2E5_=28issue_=2326796=29?= Message-ID: <20161021214205.38632.41643.9B16726C@psf.io> https://hg.python.org/cpython/rev/99941cacfc38 changeset: 104630:99941cacfc38 branch: 3.6 parent: 104627:60a57f15fb86 parent: 104629:785597e758a1 user: Yury Selivanov date: Fri Oct 21 17:41:23 2016 -0400 summary: Merge 3.5 (issue #26796) files: Doc/library/asyncio-eventloop.rst | 7 +++++++ Lib/asyncio/base_events.py | 5 +---- Misc/NEWS | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -671,6 +671,13 @@ This method is a :ref:`coroutine `. + .. versionchanged:: 3.5.3 + :meth:`BaseEventLoop.run_in_executor` no longer configures the + ``max_workers`` of the thread pool executor it creates, instead + leaving it up to the thread pool executor + (:class:`~concurrent.futures.ThreadPoolExecutor`) to set the + default. + .. method:: AbstractEventLoop.set_default_executor(executor) Set the default executor used by :meth:`run_in_executor`. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -41,9 +41,6 @@ __all__ = ['BaseEventLoop'] -# Argument for default thread pool executor creation. -_MAX_WORKERS = 5 - # Minimum number of _scheduled timer handles before cleanup of # cancelled handles is performed. _MIN_SCHEDULED_TIMER_HANDLES = 100 @@ -620,7 +617,7 @@ if executor is None: executor = self._default_executor if executor is None: - executor = concurrent.futures.ThreadPoolExecutor(_MAX_WORKERS) + executor = concurrent.futures.ThreadPoolExecutor() self._default_executor = executor return futures.wrap_future(executor.submit(func, *args), loop=self) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,10 @@ children are done. Patch by Johannes Ebke. +- Issue #26796: Don't configure the number of workers for default + threadpool executor. + Initial patch by Hans Lawrenz. + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:42:05 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:42:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2Nzk2?= =?utf-8?q?=3A_Don=27t_configure_the_number_of_workers_for_default_threadp?= =?utf-8?q?ool?= Message-ID: <20161021214205.68411.49748.A7545969@psf.io> https://hg.python.org/cpython/rev/785597e758a1 changeset: 104629:785597e758a1 branch: 3.5 parent: 104626:0b5e28042355 user: Yury Selivanov date: Fri Oct 21 17:40:42 2016 -0400 summary: Issue #26796: Don't configure the number of workers for default threadpool executor. Initial patch by Hans Lawrenz. files: Doc/library/asyncio-eventloop.rst | 7 +++++++ Lib/asyncio/base_events.py | 5 +---- Misc/NEWS | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -670,6 +670,13 @@ This method is a :ref:`coroutine `. + .. versionchanged:: 3.5.3 + :meth:`BaseEventLoop.run_in_executor` no longer configures the + ``max_workers`` of the thread pool executor it creates, instead + leaving it up to the thread pool executor + (:class:`~concurrent.futures.ThreadPoolExecutor`) to set the + default. + .. method:: AbstractEventLoop.set_default_executor(executor) Set the default executor used by :meth:`run_in_executor`. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -41,9 +41,6 @@ __all__ = ['BaseEventLoop'] -# Argument for default thread pool executor creation. -_MAX_WORKERS = 5 - # Minimum number of _scheduled timer handles before cleanup of # cancelled handles is performed. _MIN_SCHEDULED_TIMER_HANDLES = 100 @@ -616,7 +613,7 @@ if executor is None: executor = self._default_executor if executor is None: - executor = concurrent.futures.ThreadPoolExecutor(_MAX_WORKERS) + executor = concurrent.futures.ThreadPoolExecutor() self._default_executor = executor return futures.wrap_future(executor.submit(func, *args), loop=self) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -402,6 +402,10 @@ children are done. Patch by Johannes Ebke. +- Issue #26796: Don't configure the number of workers for default + threadpool executor. + Initial patch by Hans Lawrenz. + IDLE ---- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 17:42:08 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 21 Oct 2016 21:42:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjY3OTYp?= Message-ID: <20161021214205.17963.90647.FFE2AB0D@psf.io> https://hg.python.org/cpython/rev/a475f2e39c6f changeset: 104631:a475f2e39c6f parent: 104628:f1a154e59323 parent: 104630:99941cacfc38 user: Yury Selivanov date: Fri Oct 21 17:42:00 2016 -0400 summary: Merge 3.6 (issue #26796) files: Doc/library/asyncio-eventloop.rst | 7 +++++++ Lib/asyncio/base_events.py | 5 +---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -671,6 +671,13 @@ This method is a :ref:`coroutine `. + .. versionchanged:: 3.5.3 + :meth:`BaseEventLoop.run_in_executor` no longer configures the + ``max_workers`` of the thread pool executor it creates, instead + leaving it up to the thread pool executor + (:class:`~concurrent.futures.ThreadPoolExecutor`) to set the + default. + .. method:: AbstractEventLoop.set_default_executor(executor) Set the default executor used by :meth:`run_in_executor`. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -41,9 +41,6 @@ __all__ = ['BaseEventLoop'] -# Argument for default thread pool executor creation. -_MAX_WORKERS = 5 - # Minimum number of _scheduled timer handles before cleanup of # cancelled handles is performed. _MIN_SCHEDULED_TIMER_HANDLES = 100 @@ -620,7 +617,7 @@ if executor is None: executor = self._default_executor if executor is None: - executor = concurrent.futures.ThreadPoolExecutor(_MAX_WORKERS) + executor = concurrent.futures.ThreadPoolExecutor() self._default_executor = executor return futures.wrap_future(executor.submit(func, *args), loop=self) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 19:00:52 2016 From: python-checkins at python.org (martin.panter) Date: Fri, 21 Oct 2016 23:00:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323214=3A_Fix_form?= =?utf-8?q?atting_of_-1?= Message-ID: <20161021230048.27942.83703.FF4E40CE@psf.io> https://hg.python.org/cpython/rev/2af6d94de492 changeset: 104632:2af6d94de492 user: Martin Panter date: Fri Oct 21 23:00:10 2016 +0000 summary: Issue #23214: Fix formatting of -1 files: Doc/library/io.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -485,7 +485,7 @@ implementing your own buffering on top of a :class:`BufferedIOBase` object. - If *size* is ?1 (the default), an arbitrary number of bytes are + If *size* is ``-1`` (the default), an arbitrary number of bytes are returned (more than zero unless EOF is reached). .. method:: readinto(b) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 19:13:31 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 23:13:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328482=3A_Skip_a_few_test=5Ftyping_tests_if_asyn?= =?utf-8?q?cio_unavailable_=283=2E6-=3E3=2E7=29?= Message-ID: <20161021231330.110671.47450.188948F4@psf.io> https://hg.python.org/cpython/rev/c5fb5ac84f1e changeset: 104635:c5fb5ac84f1e parent: 104632:2af6d94de492 parent: 104634:8f3b4779afaf user: Guido van Rossum date: Fri Oct 21 16:13:17 2016 -0700 summary: Issue #28482: Skip a few test_typing tests if asyncio unavailable (3.6->3.7) files: Lib/test/test_typing.py | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1116,9 +1116,9 @@ blah() -PY35 = sys.version_info[:2] >= (3, 5) +ASYNCIO = sys.version_info[:2] >= (3, 5) -PY35_TESTS = """ +ASYNCIO_TESTS = """ import asyncio T_a = TypeVar('T') @@ -1149,8 +1149,11 @@ raise StopAsyncIteration """ -if PY35: - exec(PY35_TESTS) +if ASYNCIO: + try: + exec(ASYNCIO_TESTS) + except ImportError: + ASYNCIO = False PY36 = sys.version_info[:2] >= (3, 6) @@ -1253,7 +1256,7 @@ self.assertIsInstance(it, typing.Iterator) self.assertNotIsInstance(42, typing.Iterator) - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_awaitable(self): ns = {} exec( @@ -1266,7 +1269,7 @@ self.assertNotIsInstance(foo, typing.Awaitable) g.send(None) # Run foo() till completion, to avoid warning. - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterable(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) @@ -1274,7 +1277,7 @@ self.assertIsInstance(it, typing.AsyncIterable) self.assertNotIsInstance(42, typing.AsyncIterable) - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterator(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 19:13:31 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 23:13:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328482=3A_Skip_a_few_test=5Ftyping_tests_if_asyncio_un?= =?utf-8?b?YXZhaWxhYmxlICgzLjUtPjMuNik=?= Message-ID: <20161021231330.68488.79958.9EC3DB4A@psf.io> https://hg.python.org/cpython/rev/8f3b4779afaf changeset: 104634:8f3b4779afaf branch: 3.6 parent: 104630:99941cacfc38 parent: 104633:c3363f684a2d user: Guido van Rossum date: Fri Oct 21 16:12:50 2016 -0700 summary: Issue #28482: Skip a few test_typing tests if asyncio unavailable (3.5->3.6) files: Lib/test/test_typing.py | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1116,9 +1116,9 @@ blah() -PY35 = sys.version_info[:2] >= (3, 5) +ASYNCIO = sys.version_info[:2] >= (3, 5) -PY35_TESTS = """ +ASYNCIO_TESTS = """ import asyncio T_a = TypeVar('T') @@ -1149,8 +1149,11 @@ raise StopAsyncIteration """ -if PY35: - exec(PY35_TESTS) +if ASYNCIO: + try: + exec(ASYNCIO_TESTS) + except ImportError: + ASYNCIO = False PY36 = sys.version_info[:2] >= (3, 6) @@ -1253,7 +1256,7 @@ self.assertIsInstance(it, typing.Iterator) self.assertNotIsInstance(42, typing.Iterator) - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_awaitable(self): ns = {} exec( @@ -1266,7 +1269,7 @@ self.assertNotIsInstance(foo, typing.Awaitable) g.send(None) # Run foo() till completion, to avoid warning. - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterable(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) @@ -1274,7 +1277,7 @@ self.assertIsInstance(it, typing.AsyncIterable) self.assertNotIsInstance(42, typing.AsyncIterable) - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterator(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 19:13:33 2016 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Oct 2016 23:13:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDgy?= =?utf-8?q?=3A_Skip_a_few_test=5Ftyping_tests_if_asyncio_unavailable?= Message-ID: <20161021231330.9757.823.D5FA7039@psf.io> https://hg.python.org/cpython/rev/c3363f684a2d changeset: 104633:c3363f684a2d branch: 3.5 parent: 104629:785597e758a1 user: Guido van Rossum date: Fri Oct 21 16:12:17 2016 -0700 summary: Issue #28482: Skip a few test_typing tests if asyncio unavailable files: Lib/test/test_typing.py | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1116,9 +1116,9 @@ blah() -PY35 = sys.version_info[:2] >= (3, 5) +ASYNCIO = sys.version_info[:2] >= (3, 5) -PY35_TESTS = """ +ASYNCIO_TESTS = """ import asyncio T_a = TypeVar('T') @@ -1149,8 +1149,11 @@ raise StopAsyncIteration """ -if PY35: - exec(PY35_TESTS) +if ASYNCIO: + try: + exec(ASYNCIO_TESTS) + except ImportError: + ASYNCIO = False PY36 = sys.version_info[:2] >= (3, 6) @@ -1253,7 +1256,7 @@ self.assertIsInstance(it, typing.Iterator) self.assertNotIsInstance(42, typing.Iterator) - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_awaitable(self): ns = {} exec( @@ -1266,7 +1269,7 @@ self.assertNotIsInstance(foo, typing.Awaitable) g.send(None) # Run foo() till completion, to avoid warning. - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterable(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) @@ -1274,7 +1277,7 @@ self.assertIsInstance(it, typing.AsyncIterable) self.assertNotIsInstance(42, typing.AsyncIterable) - @skipUnless(PY35, 'Python 3.5 required') + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterator(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 20:34:47 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 22 Oct 2016 00:34:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Two_minor_typi?= =?utf-8?q?ng=2Epy_fixes_=28upstream_=23305=29?= Message-ID: <20161022003447.17919.76440.FE002DFD@psf.io> https://hg.python.org/cpython/rev/991fd1fec730 changeset: 104636:991fd1fec730 branch: 3.5 parent: 104633:c3363f684a2d user: Guido van Rossum date: Fri Oct 21 17:30:29 2016 -0700 summary: Two minor typing.py fixes (upstream #305) files: Lib/test/test_typing.py | 2 +- Lib/typing.py | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1182,7 +1182,7 @@ class GetTypeHintTests(BaseTestCase): @skipUnless(PY36, 'Python 3.6 required') def test_get_type_hints_modules(self): - self.assertEqual(gth(ann_module), {'x': int, 'y': str}) + self.assertEqual(gth(ann_module), {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str}) self.assertEqual(gth(ann_module2), {}) self.assertEqual(gth(ann_module3), {}) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -894,7 +894,7 @@ return arg._subs_repr(tvars, args) if isinstance(arg, TypeVar): for i, tvar in enumerate(tvars): - if arg.__name__ == tvar.__name__: + if arg == tvar: return args[i] return _type_repr(arg) @@ -1322,10 +1322,6 @@ hints = obj.__annotations__ except AttributeError: return {} - # we keep only those annotations that can be accessed on module - members = obj.__dict__ - hints = {name: value for name, value in hints.items() - if name in members} for name, value in hints.items(): if value is None: value = type(None) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 20:34:47 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 22 Oct 2016 00:34:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Two_minor_typing=2Epy_fixes_=28upstream_=23305=29_=283=2E5-=3E?= =?utf-8?q?3=2E6=29?= Message-ID: <20161022003447.11851.78001.696118A5@psf.io> https://hg.python.org/cpython/rev/02bc01e18b9c changeset: 104637:02bc01e18b9c branch: 3.6 parent: 104634:8f3b4779afaf parent: 104636:991fd1fec730 user: Guido van Rossum date: Fri Oct 21 17:30:30 2016 -0700 summary: Two minor typing.py fixes (upstream #305) (3.5->3.6) files: Lib/test/test_typing.py | 2 +- Lib/typing.py | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1182,7 +1182,7 @@ class GetTypeHintTests(BaseTestCase): @skipUnless(PY36, 'Python 3.6 required') def test_get_type_hints_modules(self): - self.assertEqual(gth(ann_module), {'x': int, 'y': str}) + self.assertEqual(gth(ann_module), {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str}) self.assertEqual(gth(ann_module2), {}) self.assertEqual(gth(ann_module3), {}) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -894,7 +894,7 @@ return arg._subs_repr(tvars, args) if isinstance(arg, TypeVar): for i, tvar in enumerate(tvars): - if arg.__name__ == tvar.__name__: + if arg == tvar: return args[i] return _type_repr(arg) @@ -1322,10 +1322,6 @@ hints = obj.__annotations__ except AttributeError: return {} - # we keep only those annotations that can be accessed on module - members = obj.__dict__ - hints = {name: value for name, value in hints.items() - if name in members} for name, value in hints.items(): if value is None: value = type(None) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 20:34:47 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 22 Oct 2016 00:34:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Two_minor_typing=2Epy_fixes_=28upstream_=23305=29_=283?= =?utf-8?b?LjYtPjMuNyk=?= Message-ID: <20161022003447.27888.71124.A24ED806@psf.io> https://hg.python.org/cpython/rev/862abf309b78 changeset: 104638:862abf309b78 parent: 104635:c5fb5ac84f1e parent: 104637:02bc01e18b9c user: Guido van Rossum date: Fri Oct 21 17:30:31 2016 -0700 summary: Two minor typing.py fixes (upstream #305) (3.6->3.7) files: Lib/test/test_typing.py | 2 +- Lib/typing.py | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1182,7 +1182,7 @@ class GetTypeHintTests(BaseTestCase): @skipUnless(PY36, 'Python 3.6 required') def test_get_type_hints_modules(self): - self.assertEqual(gth(ann_module), {'x': int, 'y': str}) + self.assertEqual(gth(ann_module), {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str}) self.assertEqual(gth(ann_module2), {}) self.assertEqual(gth(ann_module3), {}) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -894,7 +894,7 @@ return arg._subs_repr(tvars, args) if isinstance(arg, TypeVar): for i, tvar in enumerate(tvars): - if arg.__name__ == tvar.__name__: + if arg == tvar: return args[i] return _type_repr(arg) @@ -1322,10 +1322,6 @@ hints = obj.__annotations__ except AttributeError: return {} - # we keep only those annotations that can be accessed on module - members = obj.__dict__ - hints = {name: value for name, value in hints.items() - if name in members} for name, value in hints.items(): if value is None: value = type(None) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 23:22:48 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 22 Oct 2016 03:22:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4NDM1?= =?utf-8?q?=3A_Avoid_no=5Fproxy_environment_variable_interfering_with_test?= =?utf-8?q?s?= Message-ID: <20161022032248.18070.98454.E5B28065@psf.io> https://hg.python.org/cpython/rev/8f4424bdeadc changeset: 104640:8f4424bdeadc branch: 2.7 parent: 104587:cca20d28f348 user: Martin Panter date: Sat Oct 22 03:00:32 2016 +0000 summary: Issue #28435: Avoid no_proxy environment variable interfering with tests Patch by Piotr Szczepaniak. files: Lib/test/test_urllib2_localnet.py | 8 ++++++++ Misc/ACKS | 1 + 2 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -329,6 +329,14 @@ def setUp(self): super(ProxyAuthTests, self).setUp() + # Ignore proxy bypass settings in the environment. + def restore_environ(old_environ): + os.environ.clear() + os.environ.update(old_environ) + self.addCleanup(restore_environ, os.environ.copy()) + os.environ['NO_PROXY'] = '' + os.environ['no_proxy'] = '' + self.digest_auth_handler = DigestAuthHandler() self.digest_auth_handler.set_users({self.USER: self.PASSWD}) self.digest_auth_handler.set_realm(self.REALM) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1361,6 +1361,7 @@ Thenault Sylvain P?ter Szab? John Szakmeister +Piotr Szczepaniak Amir Szekely Arfrever Frehtes Taifersar Arahesis Hideaki Takahashi -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 23:22:48 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 22 Oct 2016 03:22:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDM1?= =?utf-8?q?=3A_Avoid_no=5Fproxy_environment_variable_interfering_with_test?= =?utf-8?q?s?= Message-ID: <20161022032248.16687.34174.22A23B74@psf.io> https://hg.python.org/cpython/rev/dc9ad44125de changeset: 104641:dc9ad44125de branch: 3.5 parent: 104639:d76fccbad014 user: Martin Panter date: Sat Oct 22 01:42:06 2016 +0000 summary: Issue #28435: Avoid no_proxy environment variable interfering with tests Patch by Piotr Szczepaniak. files: Lib/test/test_urllib2_localnet.py | 9 +++++++++ Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -323,6 +323,14 @@ def setUp(self): super(ProxyAuthTests, self).setUp() + # Ignore proxy bypass settings in the environment. + def restore_environ(old_environ): + os.environ.clear() + os.environ.update(old_environ) + self.addCleanup(restore_environ, os.environ.copy()) + os.environ['NO_PROXY'] = '' + os.environ['no_proxy'] = '' + self.digest_auth_handler = DigestAuthHandler() self.digest_auth_handler.set_users({self.USER: self.PASSWD}) self.digest_auth_handler.set_realm(self.REALM) @@ -445,6 +453,7 @@ os.environ.update(old_environ) self.addCleanup(restore_environ, os.environ.copy()) os.environ['NO_PROXY'] = '*' + os.environ['no_proxy'] = '*' def urlopen(self, url, data=None, **kwargs): l = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1450,6 +1450,7 @@ Thenault Sylvain P?ter Szab? John Szakmeister +Piotr Szczepaniak Amir Szekely Maciej Szulik Arfrever Frehtes Taifersar Arahesis -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 23:22:48 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 22 Oct 2016 03:22:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2NjIw?= =?utf-8?q?=3A_Fix_ResourceWarning_in_test=5Furllib2=5Flocalnet?= Message-ID: <20161022032248.27140.97133.58B127DB@psf.io> https://hg.python.org/cpython/rev/d76fccbad014 changeset: 104639:d76fccbad014 branch: 3.5 parent: 104636:991fd1fec730 user: Martin Panter date: Sat Oct 22 01:28:21 2016 +0000 summary: Issue #26620: Fix ResourceWarning in test_urllib2_localnet * Use context manager on urllib objects to ensure that they are closed on error * Use self.addCleanup() to cleanup resources even if a test is interrupted with CTRL+c This backports a patch by Victor Stinner. files: Lib/test/test_urllib2_localnet.py | 39 ++++++++---------- 1 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -289,12 +289,12 @@ def http_server_with_basic_auth_handler(*args, **kwargs): return BasicAuthHandler(*args, **kwargs) self.server = LoopbackHttpServerThread(http_server_with_basic_auth_handler) + self.addCleanup(self.server.stop) self.server_url = 'http://127.0.0.1:%s' % self.server.port self.server.start() self.server.ready.wait() def tearDown(self): - self.server.stop() super(BasicAuthTests, self).tearDown() def test_basic_auth_success(self): @@ -438,17 +438,13 @@ def setUp(self): super(TestUrlopen, self).setUp() + # Ignore proxies for localhost tests. - self.old_environ = os.environ.copy() + def restore_environ(old_environ): + os.environ.clear() + os.environ.update(old_environ) + self.addCleanup(restore_environ, os.environ.copy()) os.environ['NO_PROXY'] = '*' - self.server = None - - def tearDown(self): - if self.server is not None: - self.server.stop() - os.environ.clear() - os.environ.update(self.old_environ) - super(TestUrlopen, self).tearDown() def urlopen(self, url, data=None, **kwargs): l = [] @@ -469,6 +465,7 @@ handler = GetRequestHandler(responses) self.server = LoopbackHttpServerThread(handler) + self.addCleanup(self.server.stop) self.server.start() self.server.ready.wait() port = self.server.port @@ -592,7 +589,8 @@ handler = self.start_server() req = urllib.request.Request("http://localhost:%s/" % handler.port, headers={"Range": "bytes=20-39"}) - urllib.request.urlopen(req) + with urllib.request.urlopen(req): + pass self.assertEqual(handler.headers_received["Range"], "bytes=20-39") def test_basic(self): @@ -608,22 +606,21 @@ def test_info(self): handler = self.start_server() - try: - open_url = urllib.request.urlopen( - "http://localhost:%s" % handler.port) + open_url = urllib.request.urlopen( + "http://localhost:%s" % handler.port) + with open_url: info_obj = open_url.info() - self.assertIsInstance(info_obj, email.message.Message, - "object returned by 'info' is not an " - "instance of email.message.Message") - self.assertEqual(info_obj.get_content_subtype(), "plain") - finally: - self.server.stop() + self.assertIsInstance(info_obj, email.message.Message, + "object returned by 'info' is not an " + "instance of email.message.Message") + self.assertEqual(info_obj.get_content_subtype(), "plain") def test_geturl(self): # Make sure same URL as opened is returned by geturl. handler = self.start_server() open_url = urllib.request.urlopen("http://localhost:%s" % handler.port) - url = open_url.geturl() + with open_url: + url = open_url.geturl() self.assertEqual(url, "http://localhost:%s" % handler.port) def test_iteration(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 23:22:48 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 22 Oct 2016 03:22:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328435=3A_Merge_urllib_test_fixes_from_3=2E5_into_3=2E?= =?utf-8?q?6?= Message-ID: <20161022032248.18103.24641.81013BEB@psf.io> https://hg.python.org/cpython/rev/05c3fbaa8fcf changeset: 104642:05c3fbaa8fcf branch: 3.6 parent: 104637:02bc01e18b9c parent: 104641:dc9ad44125de user: Martin Panter date: Sat Oct 22 03:21:36 2016 +0000 summary: Issue #28435: Merge urllib test fixes from 3.5 into 3.6 files: Lib/test/test_urllib2_localnet.py | 9 +++++++++ Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -323,6 +323,14 @@ def setUp(self): super(ProxyAuthTests, self).setUp() + # Ignore proxy bypass settings in the environment. + def restore_environ(old_environ): + os.environ.clear() + os.environ.update(old_environ) + self.addCleanup(restore_environ, os.environ.copy()) + os.environ['NO_PROXY'] = '' + os.environ['no_proxy'] = '' + self.digest_auth_handler = DigestAuthHandler() self.digest_auth_handler.set_users({self.USER: self.PASSWD}) self.digest_auth_handler.set_realm(self.REALM) @@ -445,6 +453,7 @@ os.environ.update(old_environ) self.addCleanup(restore_environ, os.environ.copy()) os.environ['NO_PROXY'] = '*' + os.environ['no_proxy'] = '*' def urlopen(self, url, data=None, **kwargs): l = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1473,6 +1473,7 @@ Thenault Sylvain P?ter Szab? John Szakmeister +Piotr Szczepaniak Amir Szekely Maciej Szulik Joel Taddei -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 21 23:22:48 2016 From: python-checkins at python.org (martin.panter) Date: Sat, 22 Oct 2016 03:22:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328435=3A_Merge_urllib_test_fixes_from_3=2E6?= Message-ID: <20161022032248.9814.37763.26A9012E@psf.io> https://hg.python.org/cpython/rev/4b6e6a77e501 changeset: 104643:4b6e6a77e501 parent: 104638:862abf309b78 parent: 104642:05c3fbaa8fcf user: Martin Panter date: Sat Oct 22 03:21:55 2016 +0000 summary: Issue #28435: Merge urllib test fixes from 3.6 files: Lib/test/test_urllib2_localnet.py | 9 +++++++++ Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -323,6 +323,14 @@ def setUp(self): super(ProxyAuthTests, self).setUp() + # Ignore proxy bypass settings in the environment. + def restore_environ(old_environ): + os.environ.clear() + os.environ.update(old_environ) + self.addCleanup(restore_environ, os.environ.copy()) + os.environ['NO_PROXY'] = '' + os.environ['no_proxy'] = '' + self.digest_auth_handler = DigestAuthHandler() self.digest_auth_handler.set_users({self.USER: self.PASSWD}) self.digest_auth_handler.set_realm(self.REALM) @@ -445,6 +453,7 @@ os.environ.update(old_environ) self.addCleanup(restore_environ, os.environ.copy()) os.environ['NO_PROXY'] = '*' + os.environ['no_proxy'] = '*' def urlopen(self, url, data=None, **kwargs): l = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1475,6 +1475,7 @@ Thenault Sylvain P?ter Szab? John Szakmeister +Piotr Szczepaniak Amir Szekely Maciej Szulik Joel Taddei -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 22 10:58:08 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 22 Oct 2016 14:58:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2327989=3A_Tweak_inspect=2Eformatannotation=28=29_to_im?= =?utf-8?q?prove_pydoc_rendering_of?= Message-ID: <20161022145808.9291.75430.D982A027@psf.io> https://hg.python.org/cpython/rev/3937502c149d changeset: 104645:3937502c149d branch: 3.6 parent: 104642:05c3fbaa8fcf parent: 104644:dc030d15f80d user: Guido van Rossum date: Sat Oct 22 07:56:58 2016 -0700 summary: Issue #27989: Tweak inspect.formatannotation() to improve pydoc rendering of function annotations. Ivan L. (3.5->3.6) files: Lib/inspect.py | 2 ++ Lib/test/test_pydoc.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1140,6 +1140,8 @@ return ArgInfo(args, varargs, varkw, frame.f_locals) def formatannotation(annotation, base_module=None): + if getattr(annotation, '__module__', None) == 'typing': + return repr(annotation).replace('typing.', '') if isinstance(annotation, type): if annotation.__module__ in ('builtins', base_module): return annotation.__qualname__ 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 @@ -15,6 +15,7 @@ import test.support import time import types +import typing import unittest import urllib.parse import xml.etree @@ -820,6 +821,18 @@ expected = 'C in module %s object' % __name__ self.assertIn(expected, pydoc.render_doc(c)) + def test_typing_pydoc(self): + def foo(data: typing.List[typing.Any], + x: int) -> typing.Iterator[typing.Tuple[int, typing.Any]]: + ... + T = typing.TypeVar('T') + class C(typing.Generic[T], typing.Mapping[int, str]): ... + self.assertEqual(pydoc.render_doc(foo).splitlines()[-1], + 'f\x08fo\x08oo\x08o(data:List[Any], x:int)' + ' -> Iterator[Tuple[int, Any]]') + self.assertEqual(pydoc.render_doc(C).splitlines()[2], + 'class C\x08C(typing.Mapping)') + def test_builtin(self): for name in ('str', 'str.translate', 'builtins.str', 'builtins.str.translate'): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 22 10:58:08 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 22 Oct 2016 14:58:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3OTg5?= =?utf-8?q?=3A_Tweak_inspect=2Eformatannotation=28=29_to_improve_pydoc_ren?= =?utf-8?q?dering_of?= Message-ID: <20161022145808.9825.99912.D9A2BDCB@psf.io> https://hg.python.org/cpython/rev/dc030d15f80d changeset: 104644:dc030d15f80d branch: 3.5 parent: 104641:dc9ad44125de user: Guido van Rossum date: Sat Oct 22 07:55:18 2016 -0700 summary: Issue #27989: Tweak inspect.formatannotation() to improve pydoc rendering of function annotations. Ivan L. files: Lib/inspect.py | 2 ++ Lib/test/test_pydoc.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1152,6 +1152,8 @@ return ArgInfo(args, varargs, varkw, frame.f_locals) def formatannotation(annotation, base_module=None): + if getattr(annotation, '__module__', None) == 'typing': + return repr(annotation).replace('typing.', '') if isinstance(annotation, type): if annotation.__module__ in ('builtins', base_module): return annotation.__qualname__ 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 @@ -15,6 +15,7 @@ import test.support import time import types +import typing import unittest import urllib.parse import xml.etree @@ -815,6 +816,18 @@ expected = 'C in module %s object' % __name__ self.assertIn(expected, pydoc.render_doc(c)) + def test_typing_pydoc(self): + def foo(data: typing.List[typing.Any], + x: int) -> typing.Iterator[typing.Tuple[int, typing.Any]]: + ... + T = typing.TypeVar('T') + class C(typing.Generic[T], typing.Mapping[int, str]): ... + self.assertEqual(pydoc.render_doc(foo).splitlines()[-1], + 'f\x08fo\x08oo\x08o(data:List[Any], x:int)' + ' -> Iterator[Tuple[int, Any]]') + self.assertEqual(pydoc.render_doc(C).splitlines()[2], + 'class C\x08C(typing.Mapping)') + def test_builtin(self): for name in ('str', 'str.translate', 'builtins.str', 'builtins.str.translate'): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 22 10:58:08 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 22 Oct 2016 14:58:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327989=3A_Tweak_inspect=2Eformatannotation=28=29?= =?utf-8?q?_to_improve_pydoc_rendering_of?= Message-ID: <20161022145808.16666.15683.ABE01661@psf.io> https://hg.python.org/cpython/rev/62127e60e7b0 changeset: 104646:62127e60e7b0 parent: 104643:4b6e6a77e501 parent: 104645:3937502c149d user: Guido van Rossum date: Sat Oct 22 07:57:24 2016 -0700 summary: Issue #27989: Tweak inspect.formatannotation() to improve pydoc rendering of function annotations. Ivan L. (3.6->3.7) files: Lib/inspect.py | 2 ++ Lib/test/test_pydoc.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1140,6 +1140,8 @@ return ArgInfo(args, varargs, varkw, frame.f_locals) def formatannotation(annotation, base_module=None): + if getattr(annotation, '__module__', None) == 'typing': + return repr(annotation).replace('typing.', '') if isinstance(annotation, type): if annotation.__module__ in ('builtins', base_module): return annotation.__qualname__ 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 @@ -15,6 +15,7 @@ import test.support import time import types +import typing import unittest import urllib.parse import xml.etree @@ -820,6 +821,18 @@ expected = 'C in module %s object' % __name__ self.assertIn(expected, pydoc.render_doc(c)) + def test_typing_pydoc(self): + def foo(data: typing.List[typing.Any], + x: int) -> typing.Iterator[typing.Tuple[int, typing.Any]]: + ... + T = typing.TypeVar('T') + class C(typing.Generic[T], typing.Mapping[int, str]): ... + self.assertEqual(pydoc.render_doc(foo).splitlines()[-1], + 'f\x08fo\x08oo\x08o(data:List[Any], x:int)' + ' -> Iterator[Tuple[int, Any]]') + self.assertEqual(pydoc.render_doc(C).splitlines()[2], + 'class C\x08C(typing.Mapping)') + def test_builtin(self): for name in ('str', 'str.translate', 'builtins.str', 'builtins.str.translate'): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 22 12:58:20 2016 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 22 Oct 2016 16:58:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Reference_the_original_com?= =?utf-8?q?pact-and-ordered_proposal?= Message-ID: <20161022165820.12127.13959.2BC868EF@psf.io> https://hg.python.org/cpython/rev/3e073e7b4460 changeset: 104647:3e073e7b4460 user: Raymond Hettinger date: Sat Oct 22 09:58:14 2016 -0700 summary: Reference the original compact-and-ordered proposal files: Objects/dictobject.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -10,8 +10,9 @@ This implements the dictionary's hashtable. -As of Python 3.6, this is compact and ordered. Basic idea is described here. -https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html +As of Python 3.6, this is compact and ordered. Basic idea is described here: +* https://mail.python.org/pipermail/python-dev/2012-December/123028.html +* https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html layout: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 22 16:18:50 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 22 Oct 2016 20:18:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328504=3A_Cleanup_?= =?utf-8?q?unicode=5Fdecode=5Fcall=5Ferrorhandler=5Fwchar/writer=2E?= Message-ID: <20161022201850.17968.12427.9F44E363@psf.io> https://hg.python.org/cpython/rev/204a43c452cc changeset: 104648:204a43c452cc user: Serhiy Storchaka date: Sat Oct 22 23:18:31 2016 +0300 summary: Issue #28504: Cleanup unicode_decode_call_errorhandler_wchar/writer. Patch by Xiang Zhang. files: Objects/unicodeobject.c | 24 ++++++++---------------- 1 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4240,7 +4240,7 @@ Py_ssize_t *endinpos, PyObject **exceptionObject, const char **inptr, PyObject **output, Py_ssize_t *outpos) { - static const char *argparse = "O!n;decoding error handler must return (str, int) tuple"; + static const char *argparse = "Un;decoding error handler must return (str, int) tuple"; PyObject *restuple = NULL; PyObject *repunicode = NULL; @@ -4273,10 +4273,10 @@ if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { - PyErr_SetString(PyExc_TypeError, &argparse[4]); + PyErr_SetString(PyExc_TypeError, &argparse[3]); goto onError; } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &repunicode, &newpos)) + if (!PyArg_ParseTuple(restuple, argparse, &repunicode, &newpos)) goto onError; /* Copy back the bytes variables, which might have been modified by the @@ -4284,9 +4284,6 @@ inputobj = PyUnicodeDecodeError_GetObject(*exceptionObject); if (!inputobj) goto onError; - if (!PyBytes_Check(inputobj)) { - PyErr_Format(PyExc_TypeError, "exception attribute object must be bytes"); - } *input = PyBytes_AS_STRING(inputobj); insize = PyBytes_GET_SIZE(inputobj); *inend = *input + insize; @@ -4327,7 +4324,7 @@ *inptr = *input + newpos; /* we made it! */ - Py_XDECREF(restuple); + Py_DECREF(restuple); return 0; overflow: @@ -4348,7 +4345,7 @@ Py_ssize_t *endinpos, PyObject **exceptionObject, const char **inptr, _PyUnicodeWriter *writer /* PyObject **output, Py_ssize_t *outpos */) { - static const char *argparse = "O!n;decoding error handler must return (str, int) tuple"; + static const char *argparse = "Un;decoding error handler must return (str, int) tuple"; PyObject *restuple = NULL; PyObject *repunicode = NULL; @@ -4375,10 +4372,10 @@ if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { - PyErr_SetString(PyExc_TypeError, &argparse[4]); + PyErr_SetString(PyExc_TypeError, &argparse[3]); goto onError; } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &repunicode, &newpos)) + if (!PyArg_ParseTuple(restuple, argparse, &repunicode, &newpos)) goto onError; /* Copy back the bytes variables, which might have been modified by the @@ -4386,9 +4383,6 @@ inputobj = PyUnicodeDecodeError_GetObject(*exceptionObject); if (!inputobj) goto onError; - if (!PyBytes_Check(inputobj)) { - PyErr_Format(PyExc_TypeError, "exception attribute object must be bytes"); - } *input = PyBytes_AS_STRING(inputobj); insize = PyBytes_GET_SIZE(inputobj); *inend = *input + insize; @@ -4403,8 +4397,6 @@ goto onError; } - if (PyUnicode_READY(repunicode) < 0) - goto onError; replen = PyUnicode_GET_LENGTH(repunicode); if (replen > 1) { writer->min_length += replen - 1; @@ -4420,7 +4412,7 @@ *inptr = *input + newpos; /* we made it! */ - Py_XDECREF(restuple); + Py_DECREF(restuple); return 0; onError: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 02:45:13 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 06:45:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328510=3A_Clean_up?= =?utf-8?q?_decoding_error_handlers=2E?= Message-ID: <20161023064513.18327.16973.8C4DDAFD@psf.io> https://hg.python.org/cpython/rev/e5e05ac07aee changeset: 104649:e5e05ac07aee user: Serhiy Storchaka date: Sun Oct 23 09:44:50 2016 +0300 summary: Issue #28510: Clean up decoding error handlers. Since PyUnicodeDecodeError_GetObject() always returns bytes, following PyBytes_AsString() can be replaced with PyBytes_AS_STRING(). files: Python/codecs.c | 21 ++++++--------------- 1 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -867,17 +867,14 @@ Py_UCS4 c; if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { - unsigned char *p; + const unsigned char *p; if (PyUnicodeDecodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeDecodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeDecodeError_GetObject(exc))) return NULL; - if (!(p = (unsigned char*)PyBytes_AsString(object))) { - Py_DECREF(object); - return NULL; - } + p = (const unsigned char*)PyBytes_AS_STRING(object); res = PyUnicode_New(4 * (end - start), 127); if (res == NULL) { Py_DECREF(object); @@ -1220,7 +1217,7 @@ return restuple; } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { - unsigned char *p; + const unsigned char *p; Py_UCS4 ch = 0; if (PyUnicodeDecodeError_GetStart(exc, &start)) return NULL; @@ -1228,10 +1225,7 @@ return NULL; if (!(object = PyUnicodeDecodeError_GetObject(exc))) return NULL; - if (!(p = (unsigned char*)PyBytes_AsString(object))) { - Py_DECREF(object); - return NULL; - } + p = (const unsigned char*)PyBytes_AS_STRING(object); if (!(encode = PyUnicodeDecodeError_GetEncoding(exc))) { Py_DECREF(object); return NULL; @@ -1338,7 +1332,7 @@ } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { PyObject *str; - unsigned char *p; + const unsigned char *p; Py_UCS2 ch[4]; /* decode up to 4 bad bytes. */ int consumed = 0; if (PyUnicodeDecodeError_GetStart(exc, &start)) @@ -1347,10 +1341,7 @@ return NULL; if (!(object = PyUnicodeDecodeError_GetObject(exc))) return NULL; - if (!(p = (unsigned char*)PyBytes_AsString(object))) { - Py_DECREF(object); - return NULL; - } + p = (const unsigned char*)PyBytes_AS_STRING(object); while (consumed < 4 && consumed < end-start) { /* Refuse to escape ASCII bytes. */ if (p[start+consumed] < 128) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 05:12:31 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 09:12:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2325953=3A_re=2Esub=28=29_now_raises_an_error_for?= =?utf-8?q?_invalid_numerical_group?= Message-ID: <20161023091231.11851.25569.4315FD59@psf.io> https://hg.python.org/cpython/rev/15e3695affa2 changeset: 104651:15e3695affa2 parent: 104649:e5e05ac07aee parent: 104650:cea983246919 user: Serhiy Storchaka date: Sun Oct 23 12:12:05 2016 +0300 summary: Issue #25953: re.sub() now raises an error for invalid numerical group reference in replacement template even if the pattern is not found in the string. Error message for invalid group reference now includes the group index and the position of the reference. Based on patch by SilentGhost. files: Lib/sre_parse.py | 18 +++++++------ Lib/test/test_re.py | 43 ++++++++++++++++---------------- Misc/NEWS | 6 ++++ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -395,7 +395,7 @@ len(escape)) state.checklookbehindgroup(group, source) return GROUPREF, group - raise source.error("invalid group reference", len(escape)) + raise source.error("invalid group reference %d" % group, len(escape) - 1) if len(escape) == 2: if c in ASCIILETTERS: raise source.error("bad escape %s" % escape, len(escape)) @@ -725,8 +725,8 @@ raise source.error("bad group number", len(condname) + 1) if condgroup >= MAXGROUPS: - raise source.error("invalid group reference", - len(condname) + 1) + msg = "invalid group reference %d" % condgroup + raise source.error(msg, len(condname) + 1) state.checklookbehindgroup(condgroup, source) elif char in FLAGS or char == "-": # flags @@ -883,7 +883,9 @@ literals = [] literal = [] lappend = literal.append - def addgroup(index): + def addgroup(index, pos): + if index > pattern.groups: + raise s.error("invalid group reference %d" % index, pos) if literal: literals.append(''.join(literal)) del literal[:] @@ -916,9 +918,9 @@ raise s.error("bad character in group name %r" % name, len(name) + 1) from None if index >= MAXGROUPS: - raise s.error("invalid group reference", + raise s.error("invalid group reference %d" % index, len(name) + 1) - addgroup(index) + addgroup(index, len(name) + 1) elif c == "0": if s.next in OCTDIGITS: this += sget() @@ -939,7 +941,7 @@ 'range 0-0o377' % this, len(this)) lappend(chr(c)) if not isoctal: - addgroup(int(this[1:])) + addgroup(int(this[1:]), len(this) - 1) else: try: this = chr(ESCAPES[this][1]) @@ -966,5 +968,5 @@ for index, group in groups: literals[index] = g(group) or empty except IndexError: - raise error("invalid group reference") + raise error("invalid group reference %d" % index) return empty.join(literals) 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 @@ -5,7 +5,6 @@ import re from re import Scanner import sre_compile -import sre_constants import sys import string import traceback @@ -186,18 +185,19 @@ r'octal escape value \777 outside of ' r'range 0-0o377', 0) - self.checkTemplateError('x', r'\1', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\8', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\9', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\11', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\18', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\1a', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\90', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\99', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\118', 'x', 'invalid group reference') # r'\11' + '8' - self.checkTemplateError('x', r'\11a', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\181', 'x', 'invalid group reference') # r'\18' + '1' - self.checkTemplateError('x', r'\800', 'x', 'invalid group reference') # r'\80' + '0' + self.checkTemplateError('x', r'\1', 'x', 'invalid group reference 1', 1) + self.checkTemplateError('x', r'\8', 'x', 'invalid group reference 8', 1) + self.checkTemplateError('x', r'\9', 'x', 'invalid group reference 9', 1) + self.checkTemplateError('x', r'\11', 'x', 'invalid group reference 11', 1) + self.checkTemplateError('x', r'\18', 'x', 'invalid group reference 18', 1) + self.checkTemplateError('x', r'\1a', 'x', 'invalid group reference 1', 1) + self.checkTemplateError('x', r'\90', 'x', 'invalid group reference 90', 1) + self.checkTemplateError('x', r'\99', 'x', 'invalid group reference 99', 1) + self.checkTemplateError('x', r'\118', 'x', 'invalid group reference 11', 1) + self.checkTemplateError('x', r'\11a', 'x', 'invalid group reference 11', 1) + self.checkTemplateError('x', r'\181', 'x', 'invalid group reference 18', 1) + self.checkTemplateError('x', r'\800', 'x', 'invalid group reference 80', 1) + self.checkTemplateError('x', r'\8', '', 'invalid group reference 8', 1) # in python2.3 (etc), these loop endlessly in sre_parser.py self.assertEqual(re.sub('(((((((((((x)))))))))))', r'\11', 'x'), 'x') @@ -271,9 +271,9 @@ self.checkTemplateError('(?Px)', r'\g<1a1>', 'xx', "bad character in group name '1a1'", 3) self.checkTemplateError('(?Px)', r'\g<2>', 'xx', - 'invalid group reference') + 'invalid group reference 2', 3) self.checkTemplateError('(?Px)', r'\2', 'xx', - 'invalid group reference') + 'invalid group reference 2', 1) with self.assertRaisesRegex(IndexError, "unknown group name 'ab'"): re.sub('(?Px)', r'\g', 'xx') self.assertEqual(re.sub('(?Px)|(?Py)', r'\g', 'xx'), '') @@ -558,10 +558,11 @@ 'two branches', 10) def test_re_groupref_overflow(self): - self.checkTemplateError('()', r'\g<%s>' % sre_constants.MAXGROUPS, 'xx', - 'invalid group reference', 3) - self.checkPatternError(r'(?P)(?(%d))' % sre_constants.MAXGROUPS, - 'invalid group reference', 10) + from sre_constants import MAXGROUPS + self.checkTemplateError('()', r'\g<%s>' % MAXGROUPS, 'xx', + 'invalid group reference %d' % MAXGROUPS, 3) + self.checkPatternError(r'(?P)(?(%d))' % MAXGROUPS, + 'invalid group reference %d' % MAXGROUPS, 10) def test_re_groupref(self): self.assertEqual(re.match(r'^(\|)?([^()]+)\1$', '|a|').groups(), @@ -1007,7 +1008,7 @@ self.checkPatternError(r"\567", r'octal escape value \567 outside of ' r'range 0-0o377', 0) - self.checkPatternError(r"\911", 'invalid group reference', 0) + self.checkPatternError(r"\911", 'invalid group reference 91', 1) self.checkPatternError(r"\x1", r'incomplete escape \x1', 0) self.checkPatternError(r"\x1z", r'incomplete escape \x1', 0) self.checkPatternError(r"\u123", r'incomplete escape \u123', 0) @@ -1061,7 +1062,7 @@ self.checkPatternError(br"\567", r'octal escape value \567 outside of ' r'range 0-0o377', 0) - self.checkPatternError(br"\911", 'invalid group reference', 0) + self.checkPatternError(br"\911", 'invalid group reference 91', 1) self.checkPatternError(br"\x1", r'incomplete escape \x1', 0) self.checkPatternError(br"\x1z", r'incomplete escape \x1', 0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,12 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). +- Issue #25953: re.sub() now raises an error for invalid numerical group + reference in replacement template even if the pattern is not found in + the string. Error message for invalid group reference now includes the + group index and the position of the reference. + Based on patch by SilentGhost. + - Issue #28183: Optimize and cleanup dict iteration. - Issue #26081: Added C implementation of asyncio.Future. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 05:12:40 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 09:12:40 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI1OTUz?= =?utf-8?q?=3A_re=2Esub=28=29_now_raises_an_error_for_invalid_numerical_gr?= =?utf-8?q?oup?= Message-ID: <20161023091231.25214.24157.4D15F4E0@psf.io> https://hg.python.org/cpython/rev/cea983246919 changeset: 104650:cea983246919 branch: 3.6 parent: 104645:3937502c149d user: Serhiy Storchaka date: Sun Oct 23 12:11:19 2016 +0300 summary: Issue #25953: re.sub() now raises an error for invalid numerical group reference in replacement template even if the pattern is not found in the string. Error message for invalid group reference now includes the group index and the position of the reference. Based on patch by SilentGhost. files: Lib/sre_parse.py | 18 +++++++------ Lib/test/test_re.py | 43 ++++++++++++++++---------------- Misc/NEWS | 6 ++++ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -395,7 +395,7 @@ len(escape)) state.checklookbehindgroup(group, source) return GROUPREF, group - raise source.error("invalid group reference", len(escape)) + raise source.error("invalid group reference %d" % group, len(escape) - 1) if len(escape) == 2: if c in ASCIILETTERS: raise source.error("bad escape %s" % escape, len(escape)) @@ -725,8 +725,8 @@ raise source.error("bad group number", len(condname) + 1) if condgroup >= MAXGROUPS: - raise source.error("invalid group reference", - len(condname) + 1) + msg = "invalid group reference %d" % condgroup + raise source.error(msg, len(condname) + 1) state.checklookbehindgroup(condgroup, source) elif char in FLAGS or char == "-": # flags @@ -883,7 +883,9 @@ literals = [] literal = [] lappend = literal.append - def addgroup(index): + def addgroup(index, pos): + if index > pattern.groups: + raise s.error("invalid group reference %d" % index, pos) if literal: literals.append(''.join(literal)) del literal[:] @@ -916,9 +918,9 @@ raise s.error("bad character in group name %r" % name, len(name) + 1) from None if index >= MAXGROUPS: - raise s.error("invalid group reference", + raise s.error("invalid group reference %d" % index, len(name) + 1) - addgroup(index) + addgroup(index, len(name) + 1) elif c == "0": if s.next in OCTDIGITS: this += sget() @@ -939,7 +941,7 @@ 'range 0-0o377' % this, len(this)) lappend(chr(c)) if not isoctal: - addgroup(int(this[1:])) + addgroup(int(this[1:]), len(this) - 1) else: try: this = chr(ESCAPES[this][1]) @@ -966,5 +968,5 @@ for index, group in groups: literals[index] = g(group) or empty except IndexError: - raise error("invalid group reference") + raise error("invalid group reference %d" % index) return empty.join(literals) 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 @@ -5,7 +5,6 @@ import re from re import Scanner import sre_compile -import sre_constants import sys import string import traceback @@ -186,18 +185,19 @@ r'octal escape value \777 outside of ' r'range 0-0o377', 0) - self.checkTemplateError('x', r'\1', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\8', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\9', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\11', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\18', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\1a', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\90', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\99', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\118', 'x', 'invalid group reference') # r'\11' + '8' - self.checkTemplateError('x', r'\11a', 'x', 'invalid group reference') - self.checkTemplateError('x', r'\181', 'x', 'invalid group reference') # r'\18' + '1' - self.checkTemplateError('x', r'\800', 'x', 'invalid group reference') # r'\80' + '0' + self.checkTemplateError('x', r'\1', 'x', 'invalid group reference 1', 1) + self.checkTemplateError('x', r'\8', 'x', 'invalid group reference 8', 1) + self.checkTemplateError('x', r'\9', 'x', 'invalid group reference 9', 1) + self.checkTemplateError('x', r'\11', 'x', 'invalid group reference 11', 1) + self.checkTemplateError('x', r'\18', 'x', 'invalid group reference 18', 1) + self.checkTemplateError('x', r'\1a', 'x', 'invalid group reference 1', 1) + self.checkTemplateError('x', r'\90', 'x', 'invalid group reference 90', 1) + self.checkTemplateError('x', r'\99', 'x', 'invalid group reference 99', 1) + self.checkTemplateError('x', r'\118', 'x', 'invalid group reference 11', 1) + self.checkTemplateError('x', r'\11a', 'x', 'invalid group reference 11', 1) + self.checkTemplateError('x', r'\181', 'x', 'invalid group reference 18', 1) + self.checkTemplateError('x', r'\800', 'x', 'invalid group reference 80', 1) + self.checkTemplateError('x', r'\8', '', 'invalid group reference 8', 1) # in python2.3 (etc), these loop endlessly in sre_parser.py self.assertEqual(re.sub('(((((((((((x)))))))))))', r'\11', 'x'), 'x') @@ -271,9 +271,9 @@ self.checkTemplateError('(?Px)', r'\g<1a1>', 'xx', "bad character in group name '1a1'", 3) self.checkTemplateError('(?Px)', r'\g<2>', 'xx', - 'invalid group reference') + 'invalid group reference 2', 3) self.checkTemplateError('(?Px)', r'\2', 'xx', - 'invalid group reference') + 'invalid group reference 2', 1) with self.assertRaisesRegex(IndexError, "unknown group name 'ab'"): re.sub('(?Px)', r'\g', 'xx') self.assertEqual(re.sub('(?Px)|(?Py)', r'\g', 'xx'), '') @@ -558,10 +558,11 @@ 'two branches', 10) def test_re_groupref_overflow(self): - self.checkTemplateError('()', r'\g<%s>' % sre_constants.MAXGROUPS, 'xx', - 'invalid group reference', 3) - self.checkPatternError(r'(?P)(?(%d))' % sre_constants.MAXGROUPS, - 'invalid group reference', 10) + from sre_constants import MAXGROUPS + self.checkTemplateError('()', r'\g<%s>' % MAXGROUPS, 'xx', + 'invalid group reference %d' % MAXGROUPS, 3) + self.checkPatternError(r'(?P)(?(%d))' % MAXGROUPS, + 'invalid group reference %d' % MAXGROUPS, 10) def test_re_groupref(self): self.assertEqual(re.match(r'^(\|)?([^()]+)\1$', '|a|').groups(), @@ -1007,7 +1008,7 @@ self.checkPatternError(r"\567", r'octal escape value \567 outside of ' r'range 0-0o377', 0) - self.checkPatternError(r"\911", 'invalid group reference', 0) + self.checkPatternError(r"\911", 'invalid group reference 91', 1) self.checkPatternError(r"\x1", r'incomplete escape \x1', 0) self.checkPatternError(r"\x1z", r'incomplete escape \x1', 0) self.checkPatternError(r"\u123", r'incomplete escape \u123', 0) @@ -1061,7 +1062,7 @@ self.checkPatternError(br"\567", r'octal escape value \567 outside of ' r'range 0-0o377', 0) - self.checkPatternError(br"\911", 'invalid group reference', 0) + self.checkPatternError(br"\911", 'invalid group reference 91', 1) self.checkPatternError(br"\x1", r'incomplete escape \x1', 0) self.checkPatternError(br"\x1z", r'incomplete escape \x1', 0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,12 @@ Library ------- +- Issue #25953: re.sub() now raises an error for invalid numerical group + reference in replacement template even if the pattern is not found in + the string. Error message for invalid group reference now includes the + group index and the position of the reference. + Based on patch by SilentGhost. + - Issue #18219: Optimize csv.DictWriter for large number of columns. Patch by Mariatta Wijaya. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 06:17:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 10:17:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4MTE1?= =?utf-8?q?=3A_Added_tests_for_CLI_of_the_zipfile_module=2E?= Message-ID: <20161023101721.32968.70339.1BD837EF@psf.io> https://hg.python.org/cpython/rev/042c923c5b67 changeset: 104652:042c923c5b67 branch: 2.7 parent: 104640:8f4424bdeadc user: Serhiy Storchaka date: Sun Oct 23 13:07:48 2016 +0300 summary: Issue #28115: Added tests for CLI of the zipfile module. files: Lib/test/test_zipfile.py | 74 +++++++++++++++++++++++++++- 1 files changed, 72 insertions(+), 2 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 @@ -17,8 +17,10 @@ from random import randint, random, getrandbits from unittest import skipUnless +from test import script_helper from test.test_support import TESTFN, TESTFN_UNICODE, TESTFN_ENCODING, \ - run_unittest, findfile, unlink, rmtree, check_warnings + run_unittest, findfile, unlink, rmtree, \ + check_warnings, captured_stdout try: TESTFN_UNICODE.encode(TESTFN_ENCODING) except (UnicodeError, TypeError): @@ -1770,11 +1772,79 @@ unlink(TESTFN2) +class CommandLineTest(unittest.TestCase): + + def zipfilecmd(self, *args, **kwargs): + rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args, + **kwargs) + return out.replace(os.linesep.encode(), b'\n') + + def zipfilecmd_failure(self, *args): + return script_helper.assert_python_failure('-m', 'zipfile', *args) + + def test_test_command(self): + zip_name = findfile('zipdir.zip') + out = self.zipfilecmd('-t', zip_name) + self.assertEqual(out.rstrip(), b'Done testing') + zip_name = findfile('testtar.tar') + rc, out, err = self.zipfilecmd_failure('-t', zip_name) + self.assertEqual(out, b'') + + def test_list_command(self): + zip_name = findfile('zipdir.zip') + with captured_stdout() as t, zipfile.ZipFile(zip_name, 'r') as tf: + tf.printdir() + expected = t.getvalue().encode('ascii', 'backslashreplace') + out = self.zipfilecmd('-l', zip_name, + PYTHONIOENCODING='ascii:backslashreplace') + self.assertEqual(out, expected) + + def test_create_command(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, 'w') as f: + f.write('test 1') + os.mkdir(TESTFNDIR) + self.addCleanup(rmtree, TESTFNDIR) + with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f: + f.write('test 2') + files = [TESTFN, TESTFNDIR] + namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt'] + try: + out = self.zipfilecmd('-c', TESTFN2, *files) + self.assertEqual(out, b'') + with zipfile.ZipFile(TESTFN2) as zf: + self.assertEqual(zf.namelist(), namelist) + self.assertEqual(zf.read(namelist[0]), b'test 1') + self.assertEqual(zf.read(namelist[2]), b'test 2') + finally: + unlink(TESTFN2) + + def test_extract_command(self): + zip_name = findfile('zipdir.zip') + extdir = TESTFNDIR + os.mkdir(extdir) + try: + out = self.zipfilecmd('-e', zip_name, extdir) + self.assertEqual(out, b'') + with zipfile.ZipFile(zip_name) as zf: + for zi in zf.infolist(): + path = os.path.join(extdir, + zi.filename.replace('/', os.sep)) + if zi.filename.endswith('/'): + self.assertTrue(os.path.isdir(path)) + else: + self.assertTrue(os.path.isfile(path)) + with open(path, 'rb') as f: + self.assertEqual(f.read(), zf.read(zi)) + finally: + rmtree(extdir) + def test_main(): run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, TestWithDirectory, UniversalNewlineTests, - TestsWithRandomBinaryFiles) + TestsWithRandomBinaryFiles, CommandLineTest) + if __name__ == "__main__": test_main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 06:17:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 10:17:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MTE1?= =?utf-8?q?=3A_Added_tests_for_CLI_of_the_zipfile_module=2E?= Message-ID: <20161023101721.68647.27546.B321EBA5@psf.io> https://hg.python.org/cpython/rev/900c47c98711 changeset: 104653:900c47c98711 branch: 3.5 parent: 104644:dc030d15f80d user: Serhiy Storchaka date: Sun Oct 23 13:07:59 2016 +0300 summary: Issue #28115: Added tests for CLI of the zipfile module. files: Lib/test/test_zipfile.py | 68 +++++++++++++++++++++++++++- 1 files changed, 67 insertions(+), 1 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 @@ -12,7 +12,8 @@ from tempfile import TemporaryFile from random import randint, random, getrandbits -from test.support import (TESTFN, findfile, unlink, rmtree, +from test.support import script_helper +from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, requires_zlib, requires_bz2, requires_lzma, captured_stdout, check_warnings) @@ -2115,5 +2116,70 @@ unittest.TestCase): compression = zipfile.ZIP_LZMA + +class CommandLineTest(unittest.TestCase): + + def zipfilecmd(self, *args, **kwargs): + rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args, + **kwargs) + return out.replace(os.linesep.encode(), b'\n') + + def zipfilecmd_failure(self, *args): + return script_helper.assert_python_failure('-m', 'zipfile', *args) + + def test_test_command(self): + zip_name = findfile('zipdir.zip') + out = self.zipfilecmd('-t', zip_name) + self.assertEqual(out.rstrip(), b'Done testing') + zip_name = findfile('testtar.tar') + rc, out, err = self.zipfilecmd_failure('-t', zip_name) + self.assertEqual(out, b'') + + def test_list_command(self): + zip_name = findfile('zipdir.zip') + t = io.StringIO() + with zipfile.ZipFile(zip_name, 'r') as tf: + tf.printdir(t) + expected = t.getvalue().encode('ascii', 'backslashreplace') + out = self.zipfilecmd('-l', zip_name, + PYTHONIOENCODING='ascii:backslashreplace') + self.assertEqual(out, expected) + + def test_create_command(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, 'w') as f: + f.write('test 1') + os.mkdir(TESTFNDIR) + self.addCleanup(rmtree, TESTFNDIR) + with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f: + f.write('test 2') + files = [TESTFN, TESTFNDIR] + namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt'] + try: + out = self.zipfilecmd('-c', TESTFN2, *files) + self.assertEqual(out, b'') + with zipfile.ZipFile(TESTFN2) as zf: + self.assertEqual(zf.namelist(), namelist) + self.assertEqual(zf.read(namelist[0]), b'test 1') + self.assertEqual(zf.read(namelist[2]), b'test 2') + finally: + unlink(TESTFN2) + + def test_extract_command(self): + zip_name = findfile('zipdir.zip') + with temp_dir() as extdir: + out = self.zipfilecmd('-e', zip_name, extdir) + self.assertEqual(out, b'') + with zipfile.ZipFile(zip_name) as zf: + for zi in zf.infolist(): + path = os.path.join(extdir, + zi.filename.replace('/', os.sep)) + if zi.filename.endswith('/'): + self.assertTrue(os.path.isdir(path)) + else: + self.assertTrue(os.path.isfile(path)) + with open(path, 'rb') as f: + self.assertEqual(f.read(), zf.read(zi)) + if __name__ == "__main__": unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 06:17:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 10:17:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328115=3A_Added_tests_for_CLI_of_the_zipfile_module=2E?= Message-ID: <20161023101721.12226.24150.55606AF9@psf.io> https://hg.python.org/cpython/rev/a1975621bba2 changeset: 104654:a1975621bba2 branch: 3.6 parent: 104650:cea983246919 parent: 104653:900c47c98711 user: Serhiy Storchaka date: Sun Oct 23 13:12:39 2016 +0300 summary: Issue #28115: Added tests for CLI of the zipfile module. files: Lib/test/test_zipfile.py | 68 +++++++++++++++++++++++++++- 1 files changed, 67 insertions(+), 1 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 @@ -12,7 +12,8 @@ from tempfile import TemporaryFile from random import randint, random, getrandbits -from test.support import (TESTFN, findfile, unlink, rmtree, +from test.support import script_helper +from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, requires_zlib, requires_bz2, requires_lzma, captured_stdout, check_warnings) @@ -2041,5 +2042,70 @@ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED) self.assertEqual(zi.file_size, 0) + +class CommandLineTest(unittest.TestCase): + + def zipfilecmd(self, *args, **kwargs): + rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args, + **kwargs) + return out.replace(os.linesep.encode(), b'\n') + + def zipfilecmd_failure(self, *args): + return script_helper.assert_python_failure('-m', 'zipfile', *args) + + def test_test_command(self): + zip_name = findfile('zipdir.zip') + out = self.zipfilecmd('-t', zip_name) + self.assertEqual(out.rstrip(), b'Done testing') + zip_name = findfile('testtar.tar') + rc, out, err = self.zipfilecmd_failure('-t', zip_name) + self.assertEqual(out, b'') + + def test_list_command(self): + zip_name = findfile('zipdir.zip') + t = io.StringIO() + with zipfile.ZipFile(zip_name, 'r') as tf: + tf.printdir(t) + expected = t.getvalue().encode('ascii', 'backslashreplace') + out = self.zipfilecmd('-l', zip_name, + PYTHONIOENCODING='ascii:backslashreplace') + self.assertEqual(out, expected) + + def test_create_command(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, 'w') as f: + f.write('test 1') + os.mkdir(TESTFNDIR) + self.addCleanup(rmtree, TESTFNDIR) + with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f: + f.write('test 2') + files = [TESTFN, TESTFNDIR] + namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt'] + try: + out = self.zipfilecmd('-c', TESTFN2, *files) + self.assertEqual(out, b'') + with zipfile.ZipFile(TESTFN2) as zf: + self.assertEqual(zf.namelist(), namelist) + self.assertEqual(zf.read(namelist[0]), b'test 1') + self.assertEqual(zf.read(namelist[2]), b'test 2') + finally: + unlink(TESTFN2) + + def test_extract_command(self): + zip_name = findfile('zipdir.zip') + with temp_dir() as extdir: + out = self.zipfilecmd('-e', zip_name, extdir) + self.assertEqual(out, b'') + with zipfile.ZipFile(zip_name) as zf: + for zi in zf.infolist(): + path = os.path.join(extdir, + zi.filename.replace('/', os.sep)) + if zi.is_dir(): + self.assertTrue(os.path.isdir(path)) + else: + self.assertTrue(os.path.isfile(path)) + with open(path, 'rb') as f: + self.assertEqual(f.read(), zf.read(zi)) + if __name__ == "__main__": unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 06:17:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 10:17:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328115=3A_Added_tests_for_CLI_of_the_zipfile_mod?= =?utf-8?q?ule=2E?= Message-ID: <20161023101721.110671.72237.406DF0E0@psf.io> https://hg.python.org/cpython/rev/5edac3b55130 changeset: 104655:5edac3b55130 parent: 104651:15e3695affa2 parent: 104654:a1975621bba2 user: Serhiy Storchaka date: Sun Oct 23 13:14:27 2016 +0300 summary: Issue #28115: Added tests for CLI of the zipfile module. files: Lib/test/test_zipfile.py | 68 +++++++++++++++++++++++++++- 1 files changed, 67 insertions(+), 1 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 @@ -12,7 +12,8 @@ from tempfile import TemporaryFile from random import randint, random, getrandbits -from test.support import (TESTFN, findfile, unlink, rmtree, +from test.support import script_helper +from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, requires_zlib, requires_bz2, requires_lzma, captured_stdout, check_warnings) @@ -2041,5 +2042,70 @@ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED) self.assertEqual(zi.file_size, 0) + +class CommandLineTest(unittest.TestCase): + + def zipfilecmd(self, *args, **kwargs): + rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args, + **kwargs) + return out.replace(os.linesep.encode(), b'\n') + + def zipfilecmd_failure(self, *args): + return script_helper.assert_python_failure('-m', 'zipfile', *args) + + def test_test_command(self): + zip_name = findfile('zipdir.zip') + out = self.zipfilecmd('-t', zip_name) + self.assertEqual(out.rstrip(), b'Done testing') + zip_name = findfile('testtar.tar') + rc, out, err = self.zipfilecmd_failure('-t', zip_name) + self.assertEqual(out, b'') + + def test_list_command(self): + zip_name = findfile('zipdir.zip') + t = io.StringIO() + with zipfile.ZipFile(zip_name, 'r') as tf: + tf.printdir(t) + expected = t.getvalue().encode('ascii', 'backslashreplace') + out = self.zipfilecmd('-l', zip_name, + PYTHONIOENCODING='ascii:backslashreplace') + self.assertEqual(out, expected) + + def test_create_command(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, 'w') as f: + f.write('test 1') + os.mkdir(TESTFNDIR) + self.addCleanup(rmtree, TESTFNDIR) + with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f: + f.write('test 2') + files = [TESTFN, TESTFNDIR] + namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt'] + try: + out = self.zipfilecmd('-c', TESTFN2, *files) + self.assertEqual(out, b'') + with zipfile.ZipFile(TESTFN2) as zf: + self.assertEqual(zf.namelist(), namelist) + self.assertEqual(zf.read(namelist[0]), b'test 1') + self.assertEqual(zf.read(namelist[2]), b'test 2') + finally: + unlink(TESTFN2) + + def test_extract_command(self): + zip_name = findfile('zipdir.zip') + with temp_dir() as extdir: + out = self.zipfilecmd('-e', zip_name, extdir) + self.assertEqual(out, b'') + with zipfile.ZipFile(zip_name) as zf: + for zi in zf.infolist(): + path = os.path.join(extdir, + zi.filename.replace('/', os.sep)) + if zi.is_dir(): + self.assertTrue(os.path.isdir(path)) + else: + self.assertTrue(os.path.isfile(path)) + with open(path, 'rb') as f: + self.assertEqual(f.read(), zf.read(zi)) + if __name__ == "__main__": unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:09:19 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:09:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328115=3A_Command-?= =?utf-8?q?line_interface_of_the_zipfile_module_now_uses_argparse=2E?= Message-ID: <20161023120918.32942.59000.27BB7C30@psf.io> https://hg.python.org/cpython/rev/fa275e570d52 changeset: 104656:fa275e570d52 user: Serhiy Storchaka date: Sun Oct 23 13:32:12 2016 +0300 summary: Issue #28115: Command-line interface of the zipfile module now uses argparse. Added support of long options. files: Lib/test/test_zipfile.py | 58 +++++++++++---------- Lib/zipfile.py | 73 +++++++++++++-------------- Misc/NEWS | 3 + 3 files changed, 69 insertions(+), 65 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 @@ -2055,8 +2055,9 @@ def test_test_command(self): zip_name = findfile('zipdir.zip') - out = self.zipfilecmd('-t', zip_name) - self.assertEqual(out.rstrip(), b'Done testing') + for opt in '-t', '--test': + out = self.zipfilecmd(opt, zip_name) + self.assertEqual(out.rstrip(), b'Done testing') zip_name = findfile('testtar.tar') rc, out, err = self.zipfilecmd_failure('-t', zip_name) self.assertEqual(out, b'') @@ -2067,9 +2068,10 @@ with zipfile.ZipFile(zip_name, 'r') as tf: tf.printdir(t) expected = t.getvalue().encode('ascii', 'backslashreplace') - out = self.zipfilecmd('-l', zip_name, - PYTHONIOENCODING='ascii:backslashreplace') - self.assertEqual(out, expected) + for opt in '-l', '--list': + out = self.zipfilecmd(opt, zip_name, + PYTHONIOENCODING='ascii:backslashreplace') + self.assertEqual(out, expected) def test_create_command(self): self.addCleanup(unlink, TESTFN) @@ -2081,31 +2083,33 @@ f.write('test 2') files = [TESTFN, TESTFNDIR] namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt'] - try: - out = self.zipfilecmd('-c', TESTFN2, *files) - self.assertEqual(out, b'') - with zipfile.ZipFile(TESTFN2) as zf: - self.assertEqual(zf.namelist(), namelist) - self.assertEqual(zf.read(namelist[0]), b'test 1') - self.assertEqual(zf.read(namelist[2]), b'test 2') - finally: - unlink(TESTFN2) + for opt in '-c', '--create': + try: + out = self.zipfilecmd(opt, TESTFN2, *files) + self.assertEqual(out, b'') + with zipfile.ZipFile(TESTFN2) as zf: + self.assertEqual(zf.namelist(), namelist) + self.assertEqual(zf.read(namelist[0]), b'test 1') + self.assertEqual(zf.read(namelist[2]), b'test 2') + finally: + unlink(TESTFN2) def test_extract_command(self): zip_name = findfile('zipdir.zip') - with temp_dir() as extdir: - out = self.zipfilecmd('-e', zip_name, extdir) - self.assertEqual(out, b'') - with zipfile.ZipFile(zip_name) as zf: - for zi in zf.infolist(): - path = os.path.join(extdir, - zi.filename.replace('/', os.sep)) - if zi.is_dir(): - self.assertTrue(os.path.isdir(path)) - else: - self.assertTrue(os.path.isfile(path)) - with open(path, 'rb') as f: - self.assertEqual(f.read(), zf.read(zi)) + for opt in '-e', '--extract': + with temp_dir() as extdir: + out = self.zipfilecmd(opt, zip_name, extdir) + self.assertEqual(out, b'') + with zipfile.ZipFile(zip_name) as zf: + for zi in zf.infolist(): + path = os.path.join(extdir, + zi.filename.replace('/', os.sep)) + if zi.is_dir(): + self.assertTrue(os.path.isdir(path)) + else: + self.assertTrue(os.path.isfile(path)) + with open(path, 'rb') as f: + self.assertEqual(f.read(), zf.read(zi)) if __name__ == "__main__": unittest.main() diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1950,51 +1950,45 @@ return (fname, archivename) -def main(args = None): - import textwrap - USAGE=textwrap.dedent("""\ - Usage: - zipfile.py -l zipfile.zip # Show listing of a zipfile - zipfile.py -t zipfile.zip # Test if a zipfile is valid - zipfile.py -e zipfile.zip target # Extract zipfile into target dir - zipfile.py -c zipfile.zip src ... # Create zipfile from sources - """) - if args is None: - args = sys.argv[1:] +def main(args=None): + import argparse - if not args or args[0] not in ('-l', '-c', '-e', '-t'): - print(USAGE, file=sys.stderr) - sys.exit(1) + description = 'A simple command line interface for zipfile module.' + parser = argparse.ArgumentParser(description=description) + group = parser.add_mutually_exclusive_group() + group.add_argument('-l', '--list', metavar='', + help='Show listing of a zipfile') + group.add_argument('-e', '--extract', nargs=2, + metavar=('', ''), + help='Extract zipfile into target dir') + group.add_argument('-c', '--create', nargs='+', + metavar=('', ''), + help='Create zipfile from sources') + group.add_argument('-t', '--test', metavar='', + help='Test if a zipfile is valid') + args = parser.parse_args(args) - if args[0] == '-l': - if len(args) != 2: - print(USAGE, file=sys.stderr) - sys.exit(1) - with ZipFile(args[1], 'r') as zf: - zf.printdir() - - elif args[0] == '-t': - if len(args) != 2: - print(USAGE, file=sys.stderr) - sys.exit(1) - with ZipFile(args[1], 'r') as zf: + if args.test is not None: + src = args.test + with ZipFile(src, 'r') as zf: badfile = zf.testzip() if badfile: print("The following enclosed file is corrupted: {!r}".format(badfile)) print("Done testing") - elif args[0] == '-e': - if len(args) != 3: - print(USAGE, file=sys.stderr) - sys.exit(1) + elif args.list is not None: + src = args.list + with ZipFile(src, 'r') as zf: + zf.printdir() - with ZipFile(args[1], 'r') as zf: - zf.extractall(args[2]) + elif args.extract is not None: + src, curdir = args.extract + with ZipFile(src, 'r') as zf: + zf.extractall(curdir) - elif args[0] == '-c': - if len(args) < 3: - print(USAGE, file=sys.stderr) - sys.exit(1) + elif args.create is not None: + zip_name = args.create.pop(0) + files = args.create def addToZip(zf, path, zippath): if os.path.isfile(path): @@ -2007,8 +2001,8 @@ os.path.join(path, nm), os.path.join(zippath, nm)) # else: ignore - with ZipFile(args[1], 'w') as zf: - for path in args[2:]: + with ZipFile(zip_name, 'w') as zf: + for path in files: zippath = os.path.basename(path) if not zippath: zippath = os.path.basename(os.path.dirname(path)) @@ -2016,5 +2010,8 @@ zippath = '' addToZip(zf, path, zippath) + else: + parser.exit(2, parser.format_usage()) + if __name__ == "__main__": main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ Library ------- +- Issue #28115: Command-line interface of the zipfile module now uses argparse. + Added support of long options. + - Issue #18219: Optimize csv.DictWriter for large number of columns. Patch by Mariatta Wijaya. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:12:47 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:12:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328511=3A_Use_the_?= =?utf-8?q?=22U=22_format_instead_of_=22O!=22_in_PyArg=5FParse*=2E?= Message-ID: <20161023121245.27888.77412.A03D4F1B@psf.io> https://hg.python.org/cpython/rev/d667913a81c6 changeset: 104657:d667913a81c6 user: Serhiy Storchaka date: Sun Oct 23 15:12:25 2016 +0300 summary: Issue #28511: Use the "U" format instead of "O!" in PyArg_Parse*. files: Modules/_datetimemodule.c | 5 +-- Modules/clinic/unicodedata.c.h | 6 ++-- Modules/unicodedata.c | 7 +--- Objects/exceptions.c | 33 ++++++--------------- Objects/unicodeobject.c | 6 ++-- 5 files changed, 20 insertions(+), 37 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3243,9 +3243,8 @@ { PyObject *offset; PyObject *name = NULL; - if (PyArg_ParseTupleAndKeywords(args, kw, "O!|O!:timezone", timezone_kws, - &PyDateTime_DeltaType, &offset, - &PyUnicode_Type, &name)) + if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws, + &PyDateTime_DeltaType, &offset, &name)) return new_timezone(offset, name); return NULL; diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -306,8 +306,8 @@ const char *form; PyObject *input; - if (!PyArg_ParseTuple(args, "sO!:normalize", - &form, &PyUnicode_Type, &input)) { + if (!PyArg_ParseTuple(args, "sU:normalize", + &form, &input)) { goto exit; } return_value = unicodedata_UCD_normalize_impl(self, form, input); @@ -379,4 +379,4 @@ exit: return return_value; } -/*[clinic end generated code: output=5313ce129da87b2f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=07e93c267323a576 input=a9049054013a1b77]*/ diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -808,7 +808,7 @@ self: self form: str - unistr as input: object(subclass_of='&PyUnicode_Type') + unistr as input: unicode / Return the normal form 'form' for the Unicode string unistr. @@ -819,11 +819,8 @@ static PyObject * unicodedata_UCD_normalize_impl(PyObject *self, const char *form, PyObject *input) -/*[clinic end generated code: output=62d1f8870027efdc input=cd092e631cf11883]*/ +/*[clinic end generated code: output=62d1f8870027efdc input=1744c55f4ab79bf0]*/ { - if (PyUnicode_READY(input) == -1) - return NULL; - if (PyUnicode_GET_LENGTH(input) == 0) { /* Special case empty input strings, since resizing them later would cause internal errors. */ diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1820,18 +1820,10 @@ Py_CLEAR(err->object); Py_CLEAR(err->reason); - if (!PyArg_ParseTuple(args, "O!O!nnO!", - &PyUnicode_Type, &err->encoding, - &PyUnicode_Type, &err->object, - &err->start, - &err->end, - &PyUnicode_Type, &err->reason)) { - err->encoding = err->object = err->reason = NULL; - return -1; - } - - if (PyUnicode_READY(err->object) < -1) { - err->encoding = NULL; + if (!PyArg_ParseTuple(args, "UUnnU", + &err->encoding, &err->object, + &err->start, &err->end, &err->reason)) { + err->encoding = err->object = err->reason = NULL; return -1; } @@ -1935,12 +1927,9 @@ Py_CLEAR(ude->object); Py_CLEAR(ude->reason); - if (!PyArg_ParseTuple(args, "O!OnnO!", - &PyUnicode_Type, &ude->encoding, - &ude->object, - &ude->start, - &ude->end, - &PyUnicode_Type, &ude->reason)) { + if (!PyArg_ParseTuple(args, "UOnnU", + &ude->encoding, &ude->object, + &ude->start, &ude->end, &ude->reason)) { ude->encoding = ude->object = ude->reason = NULL; return -1; } @@ -2050,11 +2039,9 @@ Py_CLEAR(self->object); Py_CLEAR(self->reason); - if (!PyArg_ParseTuple(args, "O!nnO!", - &PyUnicode_Type, &self->object, - &self->start, - &self->end, - &PyUnicode_Type, &self->reason)) { + if (!PyArg_ParseTuple(args, "UnnU", + &self->object, + &self->start, &self->end, &self->reason)) { self->object = self->reason = NULL; return -1; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8621,7 +8621,7 @@ Py_ssize_t startpos, Py_ssize_t endpos, Py_ssize_t *newpos) { - static const char *argparse = "O!n;translating error handler must return (str, int) tuple"; + static const char *argparse = "Un;translating error handler must return (str, int) tuple"; Py_ssize_t i_newpos; PyObject *restuple; @@ -8643,11 +8643,11 @@ if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { - PyErr_SetString(PyExc_TypeError, &argparse[4]); + PyErr_SetString(PyExc_TypeError, &argparse[3]); Py_DECREF(restuple); return NULL; } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, + if (!PyArg_ParseTuple(restuple, argparse, &resunicode, &i_newpos)) { Py_DECREF(restuple); return NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:17:58 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:17:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328469=3A_timeit_n?= =?utf-8?b?b3cgdXNlcyB0aGUgc2VxdWVuY2UgMSwgMiwgNSwgMTAsIDIwLCA1MCwuLi4g?= =?utf-8?q?instead?= Message-ID: <20161023121758.9460.41815.5CD543FA@psf.io> https://hg.python.org/cpython/rev/8e6cc952adc6 changeset: 104658:8e6cc952adc6 user: Serhiy Storchaka date: Sun Oct 23 15:17:05 2016 +0300 summary: Issue #28469: timeit now uses the sequence 1, 2, 5, 10, 20, 50,... instead of 1, 10, 100,... for autoranging. files: Doc/library/timeit.rst | 23 +++++----- Lib/test/test_timeit.py | 59 +++++++++++++++++----------- Lib/timeit.py | 25 ++++++----- Misc/NEWS | 3 + 4 files changed, 63 insertions(+), 47 deletions(-) diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -28,11 +28,11 @@ .. code-block:: sh $ python3 -m timeit '"-".join(str(n) for n in range(100))' - 10000 loops, best of 3: 30.2 usec per loop + 10000 loops, best of 5: 30.2 usec per loop $ python3 -m timeit '"-".join([str(n) for n in range(100)])' - 10000 loops, best of 3: 27.5 usec per loop + 10000 loops, best of 5: 27.5 usec per loop $ python3 -m timeit '"-".join(map(str, range(100)))' - 10000 loops, best of 3: 23.2 usec per loop + 10000 loops, best of 5: 23.2 usec per loop This can be achieved from the :ref:`python-interface` with:: @@ -141,9 +141,8 @@ This is a convenience function that calls :meth:`.timeit` repeatedly so that the total time >= 0.2 second, returning the eventual (number of loops, time taken for that number of loops). It calls - :meth:`.timeit` with *number* set to successive powers of ten (10, - 100, 1000, ...) up to a maximum of one billion, until the time taken - is at least 0.2 second, or the maximum is reached. + :meth:`.timeit` with increasing numbers from the sequence 1, 2, 5, + 10, 20, 50, ... until the time taken is at least 0.2 second. If *callback* is given and is not ``None``, it will be called after each trial with two arguments: ``callback(number, time_taken)``. @@ -268,9 +267,9 @@ .. code-block:: sh $ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text' - 10000000 loops, best of 3: 0.0877 usec per loop + 5000000 loops, best of 5: 0.0877 usec per loop $ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)' - 1000000 loops, best of 3: 0.342 usec per loop + 1000000 loops, best of 5: 0.342 usec per loop :: @@ -297,14 +296,14 @@ .. code-block:: sh $ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass' - 100000 loops, best of 3: 15.7 usec per loop + 20000 loops, best of 5: 15.7 usec per loop $ python -m timeit 'if hasattr(str, "__bool__"): pass' - 100000 loops, best of 3: 4.26 usec per loop + 50000 loops, best of 5: 4.26 usec per loop $ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass' - 1000000 loops, best of 3: 1.43 usec per loop + 200000 loops, best of 5: 1.43 usec per loop $ python -m timeit 'if hasattr(int, "__bool__"): pass' - 100000 loops, best of 3: 2.23 usec per loop + 100000 loops, best of 5: 2.23 usec per loop :: diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -256,7 +256,7 @@ def test_main_milliseconds(self): s = self.run_main(seconds_per_increment=0.0055) - self.assertEqual(s, "100 loops, best of 5: 5.5 msec per loop\n") + self.assertEqual(s, "50 loops, best of 5: 5.5 msec per loop\n") def test_main_microseconds(self): s = self.run_main(seconds_per_increment=0.0000025, switches=['-n100']) @@ -304,35 +304,43 @@ """)) def test_main_very_verbose(self): - s = self.run_main(seconds_per_increment=0.000050, switches=['-vv']) + s = self.run_main(seconds_per_increment=0.000_030, switches=['-vv']) self.assertEqual(s, dedent("""\ - 1 loop -> 5e-05 secs - 10 loops -> 0.0005 secs - 100 loops -> 0.005 secs - 1000 loops -> 0.05 secs - 10000 loops -> 0.5 secs + 1 loop -> 3e-05 secs + 2 loops -> 6e-05 secs + 5 loops -> 0.00015 secs + 10 loops -> 0.0003 secs + 20 loops -> 0.0006 secs + 50 loops -> 0.0015 secs + 100 loops -> 0.003 secs + 200 loops -> 0.006 secs + 500 loops -> 0.015 secs + 1000 loops -> 0.03 secs + 2000 loops -> 0.06 secs + 5000 loops -> 0.15 secs + 10000 loops -> 0.3 secs - raw times: 500 msec, 500 msec, 500 msec, 500 msec, 500 msec + raw times: 300 msec, 300 msec, 300 msec, 300 msec, 300 msec - 10000 loops, best of 5: 50 usec per loop + 10000 loops, best of 5: 30 usec per loop """)) def test_main_with_time_unit(self): - unit_sec = self.run_main(seconds_per_increment=0.002, + unit_sec = self.run_main(seconds_per_increment=0.003, switches=['-u', 'sec']) self.assertEqual(unit_sec, - "100 loops, best of 5: 0.002 sec per loop\n") - unit_msec = self.run_main(seconds_per_increment=0.002, + "100 loops, best of 5: 0.003 sec per loop\n") + unit_msec = self.run_main(seconds_per_increment=0.003, switches=['-u', 'msec']) self.assertEqual(unit_msec, - "100 loops, best of 5: 2 msec per loop\n") - unit_usec = self.run_main(seconds_per_increment=0.002, + "100 loops, best of 5: 3 msec per loop\n") + unit_usec = self.run_main(seconds_per_increment=0.003, switches=['-u', 'usec']) self.assertEqual(unit_usec, - "100 loops, best of 5: 2e+03 usec per loop\n") + "100 loops, best of 5: 3e+03 usec per loop\n") # Test invalid unit input with captured_stderr() as error_stringio: - invalid = self.run_main(seconds_per_increment=0.002, + invalid = self.run_main(seconds_per_increment=0.003, switches=['-u', 'parsec']) self.assertEqual(error_stringio.getvalue(), "Unrecognized unit. Please select nsec, usec, msec, or sec.\n") @@ -347,15 +355,15 @@ s = self.run_main(switches=['-n1', '1/0']) self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError') - def autorange(self, seconds_per_increment=0.001, callback=None): + def autorange(self, seconds_per_increment=1/1024, callback=None): timer = FakeTimer(seconds_per_increment=seconds_per_increment) t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer) return t.autorange(callback) def test_autorange(self): num_loops, time_taken = self.autorange() - self.assertEqual(num_loops, 1000) - self.assertEqual(time_taken, 1.0) + self.assertEqual(num_loops, 500) + self.assertEqual(time_taken, 500/1024) def test_autorange_second(self): num_loops, time_taken = self.autorange(seconds_per_increment=1.0) @@ -367,12 +375,17 @@ print("{} {:.3f}".format(a, b)) with captured_stdout() as s: num_loops, time_taken = self.autorange(callback=callback) - self.assertEqual(num_loops, 1000) - self.assertEqual(time_taken, 1.0) + self.assertEqual(num_loops, 500) + self.assertEqual(time_taken, 500/1024) expected = ('1 0.001\n' + '2 0.002\n' + '5 0.005\n' '10 0.010\n' - '100 0.100\n' - '1000 1.000\n') + '20 0.020\n' + '50 0.049\n' + '100 0.098\n' + '200 0.195\n' + '500 0.488\n') self.assertEqual(s.getvalue(), expected) diff --git a/Lib/timeit.py b/Lib/timeit.py --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -208,22 +208,23 @@ def autorange(self, callback=None): """Return the number of loops so that total time >= 0.2. - Calls the timeit method with *number* set to successive powers of - ten (10, 100, 1000, ...) up to a maximum of one billion, until - the time taken is at least 0.2 second, or the maximum is reached. - Returns ``(number, time_taken)``. + Calls the timeit method with increasing numbers from the sequence + 1, 2, 5, 10, 20, 50, ... until the time taken is at least 0.2 + second. Returns (number, time_taken). If *callback* is given and is not None, it will be called after each trial with two arguments: ``callback(number, time_taken)``. """ - for i in range(0, 10): - number = 10**i - time_taken = self.timeit(number) - if callback: - callback(number, time_taken) - if time_taken >= 0.2: - break - return (number, time_taken) + i = 1 + while True: + for j in 1, 2, 5: + number = i * j + time_taken = self.timeit(number) + if callback: + callback(number, time_taken) + if time_taken >= 0.2: + return (number, time_taken) + i *= 10 def timeit(stmt="pass", setup="pass", timer=default_timer, number=default_number, globals=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ Library ------- +- Issue #28469: timeit now uses the sequence 1, 2, 5, 10, 20, 50,... instead + of 1, 10, 100,... for autoranging. + - Issue #28115: Command-line interface of the zipfile module now uses argparse. Added support of long options. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:42:15 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:42:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328439=3A_Remove_r?= =?utf-8?q?edundant_checks_in_PyUnicode=5FEncodeLocale_and?= Message-ID: <20161023124215.110871.59556.E7C84746@psf.io> https://hg.python.org/cpython/rev/94d34354bef1 changeset: 104659:94d34354bef1 user: Serhiy Storchaka date: Sun Oct 23 15:41:36 2016 +0300 summary: Issue #28439: Remove redundant checks in PyUnicode_EncodeLocale and PyUnicode_DecodeLocaleAndSize. Patch by Xiang Zhang. files: Objects/unicodeobject.c | 51 ++++++++++++---------------- 1 files changed, 22 insertions(+), 29 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3400,11 +3400,9 @@ { Py_ssize_t wlen, wlen2; wchar_t *wstr; - PyObject *bytes = NULL; char *errmsg; - PyObject *reason = NULL; - PyObject *exc; - size_t error_pos; + PyObject *bytes, *reason, *exc; + size_t error_pos, errlen; int surrogateescape; if (locale_error_handler(errors, &surrogateescape) < 0) @@ -3459,6 +3457,7 @@ len2 = wcstombs(PyBytes_AS_STRING(bytes), wstr, len+1); if (len2 == (size_t)-1 || len2 > len) { + Py_DECREF(bytes); error_pos = (size_t)-1; goto encode_error; } @@ -3474,17 +3473,15 @@ error_pos = wcstombs_errorpos(wstr); PyMem_Free(wstr); - Py_XDECREF(bytes); - - if (errmsg != NULL) { - size_t errlen; - wstr = Py_DecodeLocale(errmsg, &errlen); - if (wstr != NULL) { - reason = PyUnicode_FromWideChar(wstr, errlen); - PyMem_RawFree(wstr); - } else - errmsg = NULL; - } + + wstr = Py_DecodeLocale(errmsg, &errlen); + if (wstr != NULL) { + reason = PyUnicode_FromWideChar(wstr, errlen); + PyMem_RawFree(wstr); + } else { + errmsg = NULL; + } + if (errmsg == NULL) reason = PyUnicode_FromString( "wcstombs() encountered an unencodable " @@ -3500,7 +3497,7 @@ Py_DECREF(reason); if (exc != NULL) { PyCodec_StrictErrors(exc); - Py_XDECREF(exc); + Py_DECREF(exc); } return NULL; } @@ -3702,10 +3699,9 @@ size_t wlen, wlen2; PyObject *unicode; int surrogateescape; - size_t error_pos; + size_t error_pos, errlen; char *errmsg; - PyObject *reason = NULL; /* initialize to prevent gcc warning */ - PyObject *exc; + PyObject *exc, *reason = NULL; /* initialize to prevent gcc warning */ if (locale_error_handler(errors, &surrogateescape) < 0) return NULL; @@ -3763,19 +3759,16 @@ return unicode; decode_error: - reason = NULL; errmsg = strerror(errno); assert(errmsg != NULL); error_pos = mbstowcs_errorpos(str, len); - if (errmsg != NULL) { - size_t errlen; - wstr = Py_DecodeLocale(errmsg, &errlen); - if (wstr != NULL) { - reason = PyUnicode_FromWideChar(wstr, errlen); - PyMem_RawFree(wstr); - } - } + wstr = Py_DecodeLocale(errmsg, &errlen); + if (wstr != NULL) { + reason = PyUnicode_FromWideChar(wstr, errlen); + PyMem_RawFree(wstr); + } + if (reason == NULL) reason = PyUnicode_FromString( "mbstowcs() encountered an invalid multibyte sequence"); @@ -3790,7 +3783,7 @@ Py_DECREF(reason); if (exc != NULL) { PyCodec_StrictErrors(exc); - Py_XDECREF(exc); + Py_DECREF(exc); } return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:58:55 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:58:55 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328488=3A_shutil=2Emake=5Farchive=28=29_no_longer_adds?= =?utf-8?q?_entry_=22=2E/=22_to_ZIP_archive=2E?= Message-ID: <20161023125854.25293.79577.6EC1CEAB@psf.io> https://hg.python.org/cpython/rev/e93149fee04d changeset: 104662:e93149fee04d branch: 3.6 parent: 104654:a1975621bba2 parent: 104661:d4fce66ebe01 user: Serhiy Storchaka date: Sun Oct 23 15:57:42 2016 +0300 summary: Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. files: Lib/shutil.py | 7 ++++--- Lib/test/test_shutil.py | 13 +++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -680,9 +680,10 @@ with zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED) as zf: path = os.path.normpath(base_dir) - zf.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) + if path != os.curdir: + zf.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) for dirpath, dirnames, filenames in os.walk(base_dir): for name in sorted(dirnames): path = os.path.normpath(os.path.join(dirpath, name)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1066,6 +1066,19 @@ with support.change_cwd(work_dir): base_name = os.path.abspath(rel_base_name) + res = make_archive(rel_base_name, 'zip', root_dir) + + self.assertEqual(res, base_name + '.zip') + self.assertTrue(os.path.isfile(res)) + self.assertTrue(zipfile.is_zipfile(res)) + with zipfile.ZipFile(res) as zf: + self.assertCountEqual(zf.namelist(), + ['dist/', 'dist/sub/', 'dist/sub2/', + 'dist/file1', 'dist/file2', 'dist/sub/file3', + 'outer']) + + with support.change_cwd(work_dir): + base_name = os.path.abspath(rel_base_name) res = make_archive(rel_base_name, 'zip', root_dir, base_dir) self.assertEqual(res, base_name + '.zip') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,8 @@ Library ------- +- Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. + - Issue #25953: re.sub() now raises an error for invalid numerical group reference in replacement template even if the pattern is not found in the string. Error message for invalid group reference now includes the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:58:54 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:58:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDg4?= =?utf-8?q?=3A_shutil=2Emake=5Farchive=28=29_no_longer_adds_entry_=22=2E/?= =?utf-8?q?=22_to_ZIP_archive=2E?= Message-ID: <20161023125854.9357.94289.D6B0F2BE@psf.io> https://hg.python.org/cpython/rev/d4fce66ebe01 changeset: 104661:d4fce66ebe01 branch: 3.5 parent: 104653:900c47c98711 user: Serhiy Storchaka date: Sun Oct 23 15:55:09 2016 +0300 summary: Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. files: Lib/shutil.py | 7 ++++--- Lib/test/test_shutil.py | 13 +++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -680,9 +680,10 @@ with zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED) as zf: path = os.path.normpath(base_dir) - zf.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) + if path != os.curdir: + zf.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) for dirpath, dirnames, filenames in os.walk(base_dir): for name in sorted(dirnames): path = os.path.normpath(os.path.join(dirpath, name)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1068,6 +1068,19 @@ with support.change_cwd(work_dir): base_name = os.path.abspath(rel_base_name) + res = make_archive(rel_base_name, 'zip', root_dir) + + self.assertEqual(res, base_name + '.zip') + self.assertTrue(os.path.isfile(res)) + self.assertTrue(zipfile.is_zipfile(res)) + with zipfile.ZipFile(res) as zf: + self.assertCountEqual(zf.namelist(), + ['dist/', 'dist/sub/', 'dist/sub2/', + 'dist/file1', 'dist/file2', 'dist/sub/file3', + 'outer']) + + with support.change_cwd(work_dir): + base_name = os.path.abspath(rel_base_name) res = make_archive(rel_base_name, 'zip', root_dir, base_dir) self.assertEqual(res, base_name + '.zip') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,8 @@ Library ------- +- Issue #28488: shutil.make_archive() no longer add entry "./" to ZIP archive. + - Issue #24452: Make webbrowser support Chrome on Mac OS X. - Issue #20766: Fix references leaked by pdb in the handling of SIGINT -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:58:54 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:58:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4NDg4?= =?utf-8?q?=3A_shutil=2Emake=5Farchive=28=29_no_longer_adds_entry_=22=2E/?= =?utf-8?q?=22_to_ZIP_archive=2E?= Message-ID: <20161023125854.16819.88303.76B64F46@psf.io> https://hg.python.org/cpython/rev/847537b7924c changeset: 104660:847537b7924c branch: 2.7 parent: 104652:042c923c5b67 user: Serhiy Storchaka date: Sun Oct 23 15:52:01 2016 +0300 summary: Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. files: Lib/shutil.py | 7 ++++--- Lib/test/test_shutil.py | 13 +++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -450,9 +450,10 @@ with zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED) as zf: path = os.path.normpath(base_dir) - zf.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) + if path != os.curdir: + zf.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) for dirpath, dirnames, filenames in os.walk(base_dir): for name in sorted(dirnames): path = os.path.normpath(os.path.join(dirpath, name)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -475,6 +475,19 @@ with support.change_cwd(work_dir): base_name = os.path.abspath(rel_base_name) + res = make_archive(rel_base_name, 'zip', root_dir) + + self.assertEqual(res, base_name + '.zip') + self.assertTrue(os.path.isfile(res)) + self.assertTrue(zipfile.is_zipfile(res)) + with zipfile.ZipFile(res) as zf: + self.assertEqual(sorted(zf.namelist()), + ['dist/', 'dist/file1', 'dist/file2', + 'dist/sub/', 'dist/sub/file3', 'dist/sub2/', + 'outer']) + + with support.change_cwd(work_dir): + base_name = os.path.abspath(rel_base_name) res = make_archive(rel_base_name, 'zip', root_dir, base_dir) self.assertEqual(res, base_name + '.zip') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,8 @@ Library ------- +- Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. + - Issue #28480: Fix error building _sqlite3 module when multithreading is disabled. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 08:58:55 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 12:58:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328488=3A_shutil=2Emake=5Farchive=28=29_no_longe?= =?utf-8?q?r_adds_entry_=22=2E/=22_to_ZIP_archive=2E?= Message-ID: <20161023125855.110784.68097.82E1CDAA@psf.io> https://hg.python.org/cpython/rev/72da53d3074b changeset: 104663:72da53d3074b parent: 104659:94d34354bef1 parent: 104662:e93149fee04d user: Serhiy Storchaka date: Sun Oct 23 15:58:10 2016 +0300 summary: Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. files: Lib/shutil.py | 7 ++++--- Lib/test/test_shutil.py | 13 +++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -680,9 +680,10 @@ with zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED) as zf: path = os.path.normpath(base_dir) - zf.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) + if path != os.curdir: + zf.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) for dirpath, dirnames, filenames in os.walk(base_dir): for name in sorted(dirnames): path = os.path.normpath(os.path.join(dirpath, name)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1066,6 +1066,19 @@ with support.change_cwd(work_dir): base_name = os.path.abspath(rel_base_name) + res = make_archive(rel_base_name, 'zip', root_dir) + + self.assertEqual(res, base_name + '.zip') + self.assertTrue(os.path.isfile(res)) + self.assertTrue(zipfile.is_zipfile(res)) + with zipfile.ZipFile(res) as zf: + self.assertCountEqual(zf.namelist(), + ['dist/', 'dist/sub/', 'dist/sub2/', + 'dist/file1', 'dist/file2', 'dist/sub/file3', + 'outer']) + + with support.change_cwd(work_dir): + base_name = os.path.abspath(rel_base_name) res = make_archive(rel_base_name, 'zip', root_dir, base_dir) self.assertEqual(res, base_name + '.zip') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,8 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). +- Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. + - Issue #25953: re.sub() now raises an error for invalid numerical group reference in replacement template even if the pattern is not found in the string. Error message for invalid group reference now includes the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 15:34:04 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 19:34:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MTE1?= =?utf-8?q?=3A_ZIP_creation_test_requires_zlib=2E?= Message-ID: <20161023193403.18045.61317.31450F6B@psf.io> https://hg.python.org/cpython/rev/7701e9cb8712 changeset: 104665:7701e9cb8712 branch: 3.5 parent: 104661:d4fce66ebe01 user: Serhiy Storchaka date: Sun Oct 23 22:32:30 2016 +0300 summary: Issue #28115: ZIP creation test requires zlib. files: Lib/test/test_zipfile.py | 1 + 1 files changed, 1 insertions(+), 0 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 @@ -2145,6 +2145,7 @@ PYTHONIOENCODING='ascii:backslashreplace') self.assertEqual(out, expected) + @requires_zlib def test_create_command(self): self.addCleanup(unlink, TESTFN) with open(TESTFN, 'w') as f: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 15:34:04 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 19:34:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328115=3A_ZIP_creation_test_requires_zlib=2E?= Message-ID: <20161023193404.18383.52317.58864180@psf.io> https://hg.python.org/cpython/rev/3e7da46aead3 changeset: 104667:3e7da46aead3 parent: 104663:72da53d3074b parent: 104666:5b779441d03e user: Serhiy Storchaka date: Sun Oct 23 22:33:12 2016 +0300 summary: Issue #28115: ZIP creation test requires zlib. files: Lib/test/test_zipfile.py | 1 + 1 files changed, 1 insertions(+), 0 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 @@ -2073,6 +2073,7 @@ PYTHONIOENCODING='ascii:backslashreplace') self.assertEqual(out, expected) + @requires_zlib def test_create_command(self): self.addCleanup(unlink, TESTFN) with open(TESTFN, 'w') as f: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 15:34:03 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 19:34:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4MTE1?= =?utf-8?q?=3A_ZIP_creation_test_requires_zlib=2E?= Message-ID: <20161023193403.11886.88903.458EE877@psf.io> https://hg.python.org/cpython/rev/7f01d9d471e5 changeset: 104664:7f01d9d471e5 branch: 2.7 parent: 104660:847537b7924c user: Serhiy Storchaka date: Sun Oct 23 22:32:18 2016 +0300 summary: Issue #28115: ZIP creation test requires zlib. files: Lib/test/test_zipfile.py | 1 + 1 files changed, 1 insertions(+), 0 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 @@ -1799,6 +1799,7 @@ PYTHONIOENCODING='ascii:backslashreplace') self.assertEqual(out, expected) + @skipUnless(zlib, "requires zlib") def test_create_command(self): self.addCleanup(unlink, TESTFN) with open(TESTFN, 'w') as f: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 15:34:04 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 23 Oct 2016 19:34:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328115=3A_ZIP_creation_test_requires_zlib=2E?= Message-ID: <20161023193403.16841.7594.4249B288@psf.io> https://hg.python.org/cpython/rev/5b779441d03e changeset: 104666:5b779441d03e branch: 3.6 parent: 104662:e93149fee04d parent: 104665:7701e9cb8712 user: Serhiy Storchaka date: Sun Oct 23 22:32:48 2016 +0300 summary: Issue #28115: ZIP creation test requires zlib. files: Lib/test/test_zipfile.py | 1 + 1 files changed, 1 insertions(+), 0 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 @@ -2071,6 +2071,7 @@ PYTHONIOENCODING='ascii:backslashreplace') self.assertEqual(out, expected) + @requires_zlib def test_create_command(self): self.addCleanup(unlink, TESTFN) with open(TESTFN, 'w') as f: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 22:38:25 2016 From: python-checkins at python.org (yury.selivanov) Date: Mon, 24 Oct 2016 02:38:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogYXN5bmNpbzogSW5j?= =?utf-8?q?rease_asyncio=2EFuture_test_coverage=3B_test_both_implementatio?= =?utf-8?b?bnMu?= Message-ID: <20161024023825.12183.61855.38ABCE77@psf.io> https://hg.python.org/cpython/rev/8606c8a87bde changeset: 104668:8606c8a87bde branch: 3.6 parent: 104666:5b779441d03e user: Yury Selivanov date: Sun Oct 23 22:34:35 2016 -0400 summary: asyncio: Increase asyncio.Future test coverage; test both implementations. Also, add 'isfuture' to 'asyncio.futures.__all__', so that it's exposed as 'asyncio.isfuture'. files: Lib/asyncio/futures.py | 9 +- Lib/test/test_asyncio/test_futures.py | 156 ++++++------- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -2,7 +2,7 @@ __all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', - 'Future', 'wrap_future', + 'Future', 'wrap_future', 'isfuture' ] import concurrent.futures._base @@ -389,6 +389,10 @@ __await__ = __iter__ # make compatible with 'await' expression +# Needed for testing purposes. +_PyFuture = Future + + def _set_result_unless_cancelled(fut, result): """Helper setting the result only if the future was not cancelled.""" if fut.cancelled(): @@ -488,4 +492,5 @@ except ImportError: pass else: - Future = _asyncio.Future + # _CFuture is needed for tests. + Future = _CFuture = _asyncio.Future diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -9,6 +9,7 @@ import asyncio from asyncio import test_utils +from asyncio import futures try: from test import support except ImportError: @@ -93,14 +94,17 @@ assert g is f -class FutureTests(test_utils.TestCase): +class BaseFutureTests: + + def _new_future(self, loop=None): + raise NotImplementedError def setUp(self): self.loop = self.new_test_loop() self.addCleanup(self.loop.close) def test_initial_state(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertFalse(f.cancelled()) self.assertFalse(f.done()) f.cancel() @@ -108,15 +112,15 @@ def test_init_constructor_default_loop(self): asyncio.set_event_loop(self.loop) - f = asyncio.Future() + f = self._new_future() self.assertIs(f._loop, self.loop) def test_constructor_positional(self): # Make sure Future doesn't accept a positional argument - self.assertRaises(TypeError, asyncio.Future, 42) + self.assertRaises(TypeError, self._new_future, 42) def test_cancel(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertTrue(f.cancel()) self.assertTrue(f.cancelled()) self.assertTrue(f.done()) @@ -127,7 +131,7 @@ self.assertFalse(f.cancel()) def test_result(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.result) f.set_result(42) @@ -141,7 +145,7 @@ def test_exception(self): exc = RuntimeError() - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.exception) # StopIteration cannot be raised into a Future - CPython issue26221 @@ -158,12 +162,12 @@ self.assertFalse(f.cancel()) def test_exception_class(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_exception(RuntimeError) self.assertIsInstance(f.exception(), RuntimeError) def test_yield_from_twice(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) def fixture(): yield 'A' @@ -182,7 +186,7 @@ def test_future_repr(self): self.loop.set_debug(True) - f_pending_debug = asyncio.Future(loop=self.loop) + f_pending_debug = self._new_future(loop=self.loop) frame = f_pending_debug._source_traceback[-1] self.assertEqual(repr(f_pending_debug), '' @@ -190,21 +194,21 @@ f_pending_debug.cancel() self.loop.set_debug(False) - f_pending = asyncio.Future(loop=self.loop) + f_pending = self._new_future(loop=self.loop) self.assertEqual(repr(f_pending), '') f_pending.cancel() - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() self.assertEqual(repr(f_cancelled), '') - f_result = asyncio.Future(loop=self.loop) + f_result = self._new_future(loop=self.loop) f_result.set_result(4) self.assertEqual(repr(f_result), '') self.assertEqual(f_result.result(), 4) exc = RuntimeError() - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(exc) self.assertEqual(repr(f_exception), '') @@ -215,7 +219,7 @@ text = '%s() at %s:%s' % (func.__qualname__, filename, lineno) return re.escape(text) - f_one_callbacks = asyncio.Future(loop=self.loop) + f_one_callbacks = self._new_future(loop=self.loop) f_one_callbacks.add_done_callback(_fakefunc) fake_repr = func_repr(_fakefunc) self.assertRegex(repr(f_one_callbacks), @@ -224,7 +228,7 @@ self.assertEqual(repr(f_one_callbacks), '') - f_two_callbacks = asyncio.Future(loop=self.loop) + f_two_callbacks = self._new_future(loop=self.loop) f_two_callbacks.add_done_callback(first_cb) f_two_callbacks.add_done_callback(last_cb) first_repr = func_repr(first_cb) @@ -233,7 +237,7 @@ r'' % (first_repr, last_repr)) - f_many_callbacks = asyncio.Future(loop=self.loop) + f_many_callbacks = self._new_future(loop=self.loop) f_many_callbacks.add_done_callback(first_cb) for i in range(8): f_many_callbacks.add_done_callback(_fakefunc) @@ -248,31 +252,31 @@ def test_copy_state(self): from asyncio.futures import _copy_future_state - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_result(10) - newf = asyncio.Future(loop=self.loop) + newf = self._new_future(loop=self.loop) _copy_future_state(f, newf) self.assertTrue(newf.done()) self.assertEqual(newf.result(), 10) - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(RuntimeError()) - newf_exception = asyncio.Future(loop=self.loop) + newf_exception = self._new_future(loop=self.loop) _copy_future_state(f_exception, newf_exception) self.assertTrue(newf_exception.done()) self.assertRaises(RuntimeError, newf_exception.result) - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() - newf_cancelled = asyncio.Future(loop=self.loop) + newf_cancelled = self._new_future(loop=self.loop) _copy_future_state(f_cancelled, newf_cancelled) self.assertTrue(newf_cancelled.cancelled()) def test_iter(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) def coro(): yield from fut @@ -285,20 +289,20 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_abandoned(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) fut.result() del fut @@ -306,7 +310,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) del fut test_utils.run_briefly(self.loop) @@ -315,7 +319,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) fut.exception() del fut @@ -323,7 +327,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) self.assertRaises(RuntimeError, fut.result) del fut @@ -337,12 +341,12 @@ f1 = ex.submit(run, 'oi') f2 = asyncio.wrap_future(f1, loop=self.loop) res, ident = self.loop.run_until_complete(f2) - self.assertIsInstance(f2, asyncio.Future) + self.assertTrue(asyncio.isfuture(f2)) self.assertEqual(res, 'oi') self.assertNotEqual(ident, threading.get_ident()) def test_wrap_future_future(self): - f1 = asyncio.Future(loop=self.loop) + f1 = self._new_future(loop=self.loop) f2 = asyncio.wrap_future(f1) self.assertIs(f1, f2) @@ -377,10 +381,10 @@ def test_future_source_traceback(self): self.loop.set_debug(True) - future = asyncio.Future(loop=self.loop) + future = self._new_future(loop=self.loop) lineno = sys._getframe().f_lineno - 1 self.assertIsInstance(future._source_traceback, list) - self.assertEqual(future._source_traceback[-1][:3], + self.assertEqual(future._source_traceback[-2][:3], (__file__, lineno, 'test_future_source_traceback')) @@ -396,57 +400,18 @@ return exc exc = memory_error() - future = asyncio.Future(loop=self.loop) - if debug: - source_traceback = future._source_traceback + future = self._new_future(loop=self.loop) future.set_exception(exc) future = None test_utils.run_briefly(self.loop) support.gc_collect() if sys.version_info >= (3, 4): - if debug: - frame = source_traceback[-1] - regex = (r'^Future exception was never retrieved\n' - r'future: \n' - r'source_traceback: Object ' - r'created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future exception was never retrieved\n' - r'future: ' - r'$' - ) + regex = r'^Future exception was never retrieved\n' exc_info = (type(exc), exc, exc.__traceback__) m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: - if debug: - frame = source_traceback[-1] - regex = (r'^Future/Task exception was never retrieved\n' - r'Future/Task created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future/Task exception was never retrieved\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ) + regex = r'^Future/Task exception was never retrieved\n' m_log.error.assert_called_once_with(mock.ANY, exc_info=False) message = m_log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) @@ -458,14 +423,13 @@ self.check_future_exception_never_retrieved(True) def test_set_result_unless_cancelled(self): - from asyncio import futures - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.cancel() futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) def test_future_stop_iteration_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result((1, 2)) fi = fut.__iter__() result = None @@ -478,7 +442,21 @@ self.assertEqual(result, (1, 2)) -class FutureDoneCallbackTests(test_utils.TestCase): + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._CFuture(*args, **kwargs) + + +class PyFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._PyFuture(*args, **kwargs) + + +class BaseFutureDoneCallbackTests(): def setUp(self): self.loop = self.new_test_loop() @@ -493,7 +471,7 @@ return bag_appender def _new_future(self): - return asyncio.Future(loop=self.loop) + raise NotImplementedError def test_callbacks_invoked_on_set_result(self): bag = [] @@ -557,5 +535,21 @@ self.assertEqual(f.result(), 'foo') + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._CFuture(loop=self.loop) + + +class PyFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._PyFuture(loop=self.loop) + + if __name__ == '__main__': unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 23 22:38:27 2016 From: python-checkins at python.org (yury.selivanov) Date: Mon, 24 Oct 2016 02:38:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E6_=28asyncio=29?= Message-ID: <20161024023825.18098.2659.D99FDB5E@psf.io> https://hg.python.org/cpython/rev/de8c4673249a changeset: 104669:de8c4673249a parent: 104667:3e7da46aead3 parent: 104668:8606c8a87bde user: Yury Selivanov date: Sun Oct 23 22:35:29 2016 -0400 summary: Merge 3.6 (asyncio) files: Lib/asyncio/futures.py | 9 +- Lib/test/test_asyncio/test_futures.py | 156 ++++++------- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -2,7 +2,7 @@ __all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', - 'Future', 'wrap_future', + 'Future', 'wrap_future', 'isfuture' ] import concurrent.futures._base @@ -389,6 +389,10 @@ __await__ = __iter__ # make compatible with 'await' expression +# Needed for testing purposes. +_PyFuture = Future + + def _set_result_unless_cancelled(fut, result): """Helper setting the result only if the future was not cancelled.""" if fut.cancelled(): @@ -488,4 +492,5 @@ except ImportError: pass else: - Future = _asyncio.Future + # _CFuture is needed for tests. + Future = _CFuture = _asyncio.Future diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -9,6 +9,7 @@ import asyncio from asyncio import test_utils +from asyncio import futures try: from test import support except ImportError: @@ -93,14 +94,17 @@ assert g is f -class FutureTests(test_utils.TestCase): +class BaseFutureTests: + + def _new_future(self, loop=None): + raise NotImplementedError def setUp(self): self.loop = self.new_test_loop() self.addCleanup(self.loop.close) def test_initial_state(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertFalse(f.cancelled()) self.assertFalse(f.done()) f.cancel() @@ -108,15 +112,15 @@ def test_init_constructor_default_loop(self): asyncio.set_event_loop(self.loop) - f = asyncio.Future() + f = self._new_future() self.assertIs(f._loop, self.loop) def test_constructor_positional(self): # Make sure Future doesn't accept a positional argument - self.assertRaises(TypeError, asyncio.Future, 42) + self.assertRaises(TypeError, self._new_future, 42) def test_cancel(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertTrue(f.cancel()) self.assertTrue(f.cancelled()) self.assertTrue(f.done()) @@ -127,7 +131,7 @@ self.assertFalse(f.cancel()) def test_result(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.result) f.set_result(42) @@ -141,7 +145,7 @@ def test_exception(self): exc = RuntimeError() - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.exception) # StopIteration cannot be raised into a Future - CPython issue26221 @@ -158,12 +162,12 @@ self.assertFalse(f.cancel()) def test_exception_class(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_exception(RuntimeError) self.assertIsInstance(f.exception(), RuntimeError) def test_yield_from_twice(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) def fixture(): yield 'A' @@ -182,7 +186,7 @@ def test_future_repr(self): self.loop.set_debug(True) - f_pending_debug = asyncio.Future(loop=self.loop) + f_pending_debug = self._new_future(loop=self.loop) frame = f_pending_debug._source_traceback[-1] self.assertEqual(repr(f_pending_debug), '' @@ -190,21 +194,21 @@ f_pending_debug.cancel() self.loop.set_debug(False) - f_pending = asyncio.Future(loop=self.loop) + f_pending = self._new_future(loop=self.loop) self.assertEqual(repr(f_pending), '') f_pending.cancel() - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() self.assertEqual(repr(f_cancelled), '') - f_result = asyncio.Future(loop=self.loop) + f_result = self._new_future(loop=self.loop) f_result.set_result(4) self.assertEqual(repr(f_result), '') self.assertEqual(f_result.result(), 4) exc = RuntimeError() - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(exc) self.assertEqual(repr(f_exception), '') @@ -215,7 +219,7 @@ text = '%s() at %s:%s' % (func.__qualname__, filename, lineno) return re.escape(text) - f_one_callbacks = asyncio.Future(loop=self.loop) + f_one_callbacks = self._new_future(loop=self.loop) f_one_callbacks.add_done_callback(_fakefunc) fake_repr = func_repr(_fakefunc) self.assertRegex(repr(f_one_callbacks), @@ -224,7 +228,7 @@ self.assertEqual(repr(f_one_callbacks), '') - f_two_callbacks = asyncio.Future(loop=self.loop) + f_two_callbacks = self._new_future(loop=self.loop) f_two_callbacks.add_done_callback(first_cb) f_two_callbacks.add_done_callback(last_cb) first_repr = func_repr(first_cb) @@ -233,7 +237,7 @@ r'' % (first_repr, last_repr)) - f_many_callbacks = asyncio.Future(loop=self.loop) + f_many_callbacks = self._new_future(loop=self.loop) f_many_callbacks.add_done_callback(first_cb) for i in range(8): f_many_callbacks.add_done_callback(_fakefunc) @@ -248,31 +252,31 @@ def test_copy_state(self): from asyncio.futures import _copy_future_state - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_result(10) - newf = asyncio.Future(loop=self.loop) + newf = self._new_future(loop=self.loop) _copy_future_state(f, newf) self.assertTrue(newf.done()) self.assertEqual(newf.result(), 10) - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(RuntimeError()) - newf_exception = asyncio.Future(loop=self.loop) + newf_exception = self._new_future(loop=self.loop) _copy_future_state(f_exception, newf_exception) self.assertTrue(newf_exception.done()) self.assertRaises(RuntimeError, newf_exception.result) - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() - newf_cancelled = asyncio.Future(loop=self.loop) + newf_cancelled = self._new_future(loop=self.loop) _copy_future_state(f_cancelled, newf_cancelled) self.assertTrue(newf_cancelled.cancelled()) def test_iter(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) def coro(): yield from fut @@ -285,20 +289,20 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_abandoned(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) fut.result() del fut @@ -306,7 +310,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) del fut test_utils.run_briefly(self.loop) @@ -315,7 +319,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) fut.exception() del fut @@ -323,7 +327,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) self.assertRaises(RuntimeError, fut.result) del fut @@ -337,12 +341,12 @@ f1 = ex.submit(run, 'oi') f2 = asyncio.wrap_future(f1, loop=self.loop) res, ident = self.loop.run_until_complete(f2) - self.assertIsInstance(f2, asyncio.Future) + self.assertTrue(asyncio.isfuture(f2)) self.assertEqual(res, 'oi') self.assertNotEqual(ident, threading.get_ident()) def test_wrap_future_future(self): - f1 = asyncio.Future(loop=self.loop) + f1 = self._new_future(loop=self.loop) f2 = asyncio.wrap_future(f1) self.assertIs(f1, f2) @@ -377,10 +381,10 @@ def test_future_source_traceback(self): self.loop.set_debug(True) - future = asyncio.Future(loop=self.loop) + future = self._new_future(loop=self.loop) lineno = sys._getframe().f_lineno - 1 self.assertIsInstance(future._source_traceback, list) - self.assertEqual(future._source_traceback[-1][:3], + self.assertEqual(future._source_traceback[-2][:3], (__file__, lineno, 'test_future_source_traceback')) @@ -396,57 +400,18 @@ return exc exc = memory_error() - future = asyncio.Future(loop=self.loop) - if debug: - source_traceback = future._source_traceback + future = self._new_future(loop=self.loop) future.set_exception(exc) future = None test_utils.run_briefly(self.loop) support.gc_collect() if sys.version_info >= (3, 4): - if debug: - frame = source_traceback[-1] - regex = (r'^Future exception was never retrieved\n' - r'future: \n' - r'source_traceback: Object ' - r'created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future exception was never retrieved\n' - r'future: ' - r'$' - ) + regex = r'^Future exception was never retrieved\n' exc_info = (type(exc), exc, exc.__traceback__) m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: - if debug: - frame = source_traceback[-1] - regex = (r'^Future/Task exception was never retrieved\n' - r'Future/Task created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future/Task exception was never retrieved\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ) + regex = r'^Future/Task exception was never retrieved\n' m_log.error.assert_called_once_with(mock.ANY, exc_info=False) message = m_log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) @@ -458,14 +423,13 @@ self.check_future_exception_never_retrieved(True) def test_set_result_unless_cancelled(self): - from asyncio import futures - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.cancel() futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) def test_future_stop_iteration_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result((1, 2)) fi = fut.__iter__() result = None @@ -478,7 +442,21 @@ self.assertEqual(result, (1, 2)) -class FutureDoneCallbackTests(test_utils.TestCase): + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._CFuture(*args, **kwargs) + + +class PyFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._PyFuture(*args, **kwargs) + + +class BaseFutureDoneCallbackTests(): def setUp(self): self.loop = self.new_test_loop() @@ -493,7 +471,7 @@ return bag_appender def _new_future(self): - return asyncio.Future(loop=self.loop) + raise NotImplementedError def test_callbacks_invoked_on_set_result(self): bag = [] @@ -557,5 +535,21 @@ self.assertEqual(f.result(), 'foo') + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._CFuture(loop=self.loop) + + +class PyFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._PyFuture(loop=self.loop) + + if __name__ == '__main__': unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161024115421.68647.65324.8354CEC3@psf.io> https://hg.python.org/cpython/rev/c5f40d0b7faa changeset: 104676:c5f40d0b7faa parent: 104675:7e65a78b3aac parent: 104674:081329cca21f user: Serhiy Storchaka date: Mon Oct 24 14:53:58 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Some_distutils?= =?utf-8?q?_tests_require_zlib_for_creating_tar=2Egz_source_distribution?= =?utf-8?q?=2E?= Message-ID: <20161024115420.38659.29382.BCD461C7@psf.io> https://hg.python.org/cpython/rev/bb9cea3c3e2c changeset: 104671:bb9cea3c3e2c branch: 3.5 parent: 104665:7701e9cb8712 user: Serhiy Storchaka date: Sun Oct 23 22:56:14 2016 +0300 summary: Some distutils tests require zlib for creating tar.gz source distribution. files: Lib/distutils/tests/test_bdist_rpm.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_rpm.py b/Lib/distutils/tests/test_bdist_rpm.py --- a/Lib/distutils/tests/test_bdist_rpm.py +++ b/Lib/distutils/tests/test_bdist_rpm.py @@ -3,9 +3,7 @@ import unittest import sys import os -import tempfile -import shutil -from test.support import run_unittest +from test.support import run_unittest, requires_zlib from distutils.core import Distribution from distutils.command.bdist_rpm import bdist_rpm @@ -48,6 +46,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') @unittest.skipIf(find_executable('rpmbuild') is None, @@ -90,6 +89,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib # http://bugs.python.org/issue1533164 @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy42IC0+IDMuNik6?= =?utf-8?q?_Merge_heads?= Message-ID: <20161024115421.68416.87801.9707A84A@psf.io> https://hg.python.org/cpython/rev/081329cca21f changeset: 104674:081329cca21f branch: 3.6 parent: 104672:7ca0ce963d64 parent: 104668:8606c8a87bde user: Serhiy Storchaka date: Mon Oct 24 14:53:25 2016 +0300 summary: Merge heads files: Lib/asyncio/futures.py | 9 +- Lib/test/test_asyncio/test_futures.py | 156 ++++++------- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -2,7 +2,7 @@ __all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', - 'Future', 'wrap_future', + 'Future', 'wrap_future', 'isfuture' ] import concurrent.futures._base @@ -389,6 +389,10 @@ __await__ = __iter__ # make compatible with 'await' expression +# Needed for testing purposes. +_PyFuture = Future + + def _set_result_unless_cancelled(fut, result): """Helper setting the result only if the future was not cancelled.""" if fut.cancelled(): @@ -488,4 +492,5 @@ except ImportError: pass else: - Future = _asyncio.Future + # _CFuture is needed for tests. + Future = _CFuture = _asyncio.Future diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -9,6 +9,7 @@ import asyncio from asyncio import test_utils +from asyncio import futures try: from test import support except ImportError: @@ -93,14 +94,17 @@ assert g is f -class FutureTests(test_utils.TestCase): +class BaseFutureTests: + + def _new_future(self, loop=None): + raise NotImplementedError def setUp(self): self.loop = self.new_test_loop() self.addCleanup(self.loop.close) def test_initial_state(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertFalse(f.cancelled()) self.assertFalse(f.done()) f.cancel() @@ -108,15 +112,15 @@ def test_init_constructor_default_loop(self): asyncio.set_event_loop(self.loop) - f = asyncio.Future() + f = self._new_future() self.assertIs(f._loop, self.loop) def test_constructor_positional(self): # Make sure Future doesn't accept a positional argument - self.assertRaises(TypeError, asyncio.Future, 42) + self.assertRaises(TypeError, self._new_future, 42) def test_cancel(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertTrue(f.cancel()) self.assertTrue(f.cancelled()) self.assertTrue(f.done()) @@ -127,7 +131,7 @@ self.assertFalse(f.cancel()) def test_result(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.result) f.set_result(42) @@ -141,7 +145,7 @@ def test_exception(self): exc = RuntimeError() - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.exception) # StopIteration cannot be raised into a Future - CPython issue26221 @@ -158,12 +162,12 @@ self.assertFalse(f.cancel()) def test_exception_class(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_exception(RuntimeError) self.assertIsInstance(f.exception(), RuntimeError) def test_yield_from_twice(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) def fixture(): yield 'A' @@ -182,7 +186,7 @@ def test_future_repr(self): self.loop.set_debug(True) - f_pending_debug = asyncio.Future(loop=self.loop) + f_pending_debug = self._new_future(loop=self.loop) frame = f_pending_debug._source_traceback[-1] self.assertEqual(repr(f_pending_debug), '' @@ -190,21 +194,21 @@ f_pending_debug.cancel() self.loop.set_debug(False) - f_pending = asyncio.Future(loop=self.loop) + f_pending = self._new_future(loop=self.loop) self.assertEqual(repr(f_pending), '') f_pending.cancel() - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() self.assertEqual(repr(f_cancelled), '') - f_result = asyncio.Future(loop=self.loop) + f_result = self._new_future(loop=self.loop) f_result.set_result(4) self.assertEqual(repr(f_result), '') self.assertEqual(f_result.result(), 4) exc = RuntimeError() - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(exc) self.assertEqual(repr(f_exception), '') @@ -215,7 +219,7 @@ text = '%s() at %s:%s' % (func.__qualname__, filename, lineno) return re.escape(text) - f_one_callbacks = asyncio.Future(loop=self.loop) + f_one_callbacks = self._new_future(loop=self.loop) f_one_callbacks.add_done_callback(_fakefunc) fake_repr = func_repr(_fakefunc) self.assertRegex(repr(f_one_callbacks), @@ -224,7 +228,7 @@ self.assertEqual(repr(f_one_callbacks), '') - f_two_callbacks = asyncio.Future(loop=self.loop) + f_two_callbacks = self._new_future(loop=self.loop) f_two_callbacks.add_done_callback(first_cb) f_two_callbacks.add_done_callback(last_cb) first_repr = func_repr(first_cb) @@ -233,7 +237,7 @@ r'' % (first_repr, last_repr)) - f_many_callbacks = asyncio.Future(loop=self.loop) + f_many_callbacks = self._new_future(loop=self.loop) f_many_callbacks.add_done_callback(first_cb) for i in range(8): f_many_callbacks.add_done_callback(_fakefunc) @@ -248,31 +252,31 @@ def test_copy_state(self): from asyncio.futures import _copy_future_state - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_result(10) - newf = asyncio.Future(loop=self.loop) + newf = self._new_future(loop=self.loop) _copy_future_state(f, newf) self.assertTrue(newf.done()) self.assertEqual(newf.result(), 10) - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(RuntimeError()) - newf_exception = asyncio.Future(loop=self.loop) + newf_exception = self._new_future(loop=self.loop) _copy_future_state(f_exception, newf_exception) self.assertTrue(newf_exception.done()) self.assertRaises(RuntimeError, newf_exception.result) - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() - newf_cancelled = asyncio.Future(loop=self.loop) + newf_cancelled = self._new_future(loop=self.loop) _copy_future_state(f_cancelled, newf_cancelled) self.assertTrue(newf_cancelled.cancelled()) def test_iter(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) def coro(): yield from fut @@ -285,20 +289,20 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_abandoned(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) fut.result() del fut @@ -306,7 +310,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) del fut test_utils.run_briefly(self.loop) @@ -315,7 +319,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) fut.exception() del fut @@ -323,7 +327,7 @@ @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) self.assertRaises(RuntimeError, fut.result) del fut @@ -337,12 +341,12 @@ f1 = ex.submit(run, 'oi') f2 = asyncio.wrap_future(f1, loop=self.loop) res, ident = self.loop.run_until_complete(f2) - self.assertIsInstance(f2, asyncio.Future) + self.assertTrue(asyncio.isfuture(f2)) self.assertEqual(res, 'oi') self.assertNotEqual(ident, threading.get_ident()) def test_wrap_future_future(self): - f1 = asyncio.Future(loop=self.loop) + f1 = self._new_future(loop=self.loop) f2 = asyncio.wrap_future(f1) self.assertIs(f1, f2) @@ -377,10 +381,10 @@ def test_future_source_traceback(self): self.loop.set_debug(True) - future = asyncio.Future(loop=self.loop) + future = self._new_future(loop=self.loop) lineno = sys._getframe().f_lineno - 1 self.assertIsInstance(future._source_traceback, list) - self.assertEqual(future._source_traceback[-1][:3], + self.assertEqual(future._source_traceback[-2][:3], (__file__, lineno, 'test_future_source_traceback')) @@ -396,57 +400,18 @@ return exc exc = memory_error() - future = asyncio.Future(loop=self.loop) - if debug: - source_traceback = future._source_traceback + future = self._new_future(loop=self.loop) future.set_exception(exc) future = None test_utils.run_briefly(self.loop) support.gc_collect() if sys.version_info >= (3, 4): - if debug: - frame = source_traceback[-1] - regex = (r'^Future exception was never retrieved\n' - r'future: \n' - r'source_traceback: Object ' - r'created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future exception was never retrieved\n' - r'future: ' - r'$' - ) + regex = r'^Future exception was never retrieved\n' exc_info = (type(exc), exc, exc.__traceback__) m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: - if debug: - frame = source_traceback[-1] - regex = (r'^Future/Task exception was never retrieved\n' - r'Future/Task created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future/Task exception was never retrieved\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ) + regex = r'^Future/Task exception was never retrieved\n' m_log.error.assert_called_once_with(mock.ANY, exc_info=False) message = m_log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) @@ -458,14 +423,13 @@ self.check_future_exception_never_retrieved(True) def test_set_result_unless_cancelled(self): - from asyncio import futures - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.cancel() futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) def test_future_stop_iteration_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result((1, 2)) fi = fut.__iter__() result = None @@ -478,7 +442,21 @@ self.assertEqual(result, (1, 2)) -class FutureDoneCallbackTests(test_utils.TestCase): + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._CFuture(*args, **kwargs) + + +class PyFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._PyFuture(*args, **kwargs) + + +class BaseFutureDoneCallbackTests(): def setUp(self): self.loop = self.new_test_loop() @@ -493,7 +471,7 @@ return bag_appender def _new_future(self): - return asyncio.Future(loop=self.loop) + raise NotImplementedError def test_callbacks_invoked_on_set_result(self): bag = [] @@ -557,5 +535,21 @@ self.assertEqual(f.result(), 'foo') + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._CFuture(loop=self.loop) + + +class PyFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._PyFuture(loop=self.loop) + + if __name__ == '__main__': unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <20161024115421.25236.73662.0ECB5004@psf.io> https://hg.python.org/cpython/rev/7e65a78b3aac changeset: 104675:7e65a78b3aac parent: 104669:de8c4673249a parent: 104673:59dbf2a6e7a4 user: Serhiy Storchaka date: Mon Oct 24 14:53:36 2016 +0300 summary: Merge heads files: Lib/distutils/tests/test_bdist_rpm.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_rpm.py b/Lib/distutils/tests/test_bdist_rpm.py --- a/Lib/distutils/tests/test_bdist_rpm.py +++ b/Lib/distutils/tests/test_bdist_rpm.py @@ -3,7 +3,7 @@ import unittest import sys import os -from test.support import run_unittest +from test.support import run_unittest, requires_zlib from distutils.core import Distribution from distutils.command.bdist_rpm import bdist_rpm @@ -44,6 +44,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') @unittest.skipIf(find_executable('rpmbuild') is None, @@ -86,6 +87,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib # http://bugs.python.org/issue1533164 @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Some_distutils_tests_require_zlib_for_creating_tar=2Egz_source?= =?utf-8?q?_distribution=2E?= Message-ID: <20161024115420.27293.8619.A7C64731@psf.io> https://hg.python.org/cpython/rev/7ca0ce963d64 changeset: 104672:7ca0ce963d64 branch: 3.6 parent: 104666:5b779441d03e parent: 104671:bb9cea3c3e2c user: Serhiy Storchaka date: Sun Oct 23 22:58:06 2016 +0300 summary: Some distutils tests require zlib for creating tar.gz source distribution. files: Lib/distutils/tests/test_bdist_rpm.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_rpm.py b/Lib/distutils/tests/test_bdist_rpm.py --- a/Lib/distutils/tests/test_bdist_rpm.py +++ b/Lib/distutils/tests/test_bdist_rpm.py @@ -3,7 +3,7 @@ import unittest import sys import os -from test.support import run_unittest +from test.support import run_unittest, requires_zlib from distutils.core import Distribution from distutils.command.bdist_rpm import bdist_rpm @@ -44,6 +44,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') @unittest.skipIf(find_executable('rpmbuild') is None, @@ -86,6 +87,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib # http://bugs.python.org/issue1533164 @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Some_distutils_tests_require_zlib_for_creating_tar=2Egz_?= =?utf-8?q?source_distribution=2E?= Message-ID: <20161024115420.27387.3388.85D07050@psf.io> https://hg.python.org/cpython/rev/59dbf2a6e7a4 changeset: 104673:59dbf2a6e7a4 parent: 104667:3e7da46aead3 parent: 104672:7ca0ce963d64 user: Serhiy Storchaka date: Sun Oct 23 22:58:23 2016 +0300 summary: Some distutils tests require zlib for creating tar.gz source distribution. files: Lib/distutils/tests/test_bdist_rpm.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_rpm.py b/Lib/distutils/tests/test_bdist_rpm.py --- a/Lib/distutils/tests/test_bdist_rpm.py +++ b/Lib/distutils/tests/test_bdist_rpm.py @@ -3,7 +3,7 @@ import unittest import sys import os -from test.support import run_unittest +from test.support import run_unittest, requires_zlib from distutils.core import Distribution from distutils.command.bdist_rpm import bdist_rpm @@ -44,6 +44,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') @unittest.skipIf(find_executable('rpmbuild') is None, @@ -86,6 +87,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @requires_zlib # http://bugs.python.org/issue1533164 @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 07:54:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 11:54:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Some_distutils?= =?utf-8?q?_tests_require_zlib_for_creating_tar=2Egz_source_distribution?= =?utf-8?q?=2E?= Message-ID: <20161024115420.25236.64048.97FAB1D6@psf.io> https://hg.python.org/cpython/rev/1a7452e0d852 changeset: 104670:1a7452e0d852 branch: 2.7 parent: 104664:7f01d9d471e5 user: Serhiy Storchaka date: Sun Oct 23 22:54:43 2016 +0300 summary: Some distutils tests require zlib for creating tar.gz source distribution. files: Lib/distutils/tests/test_bdist_rpm.py | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_rpm.py b/Lib/distutils/tests/test_bdist_rpm.py --- a/Lib/distutils/tests/test_bdist_rpm.py +++ b/Lib/distutils/tests/test_bdist_rpm.py @@ -8,6 +8,11 @@ from test.test_support import run_unittest +try: + import zlib +except ImportError: + zlib = None + from distutils.core import Distribution from distutils.command.bdist_rpm import bdist_rpm from distutils.tests import support @@ -44,6 +49,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @unittest.skipUnless(zlib, "requires zlib") @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') @unittest.skipIf(find_executable('rpmbuild') is None, @@ -86,6 +92,7 @@ # spurious sdtout/stderr output under Mac OS X @unittest.skipUnless(sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X') + @unittest.skipUnless(zlib, "requires zlib") # http://bugs.python.org/issue1533164 @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Mon Oct 24 08:49:27 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 24 Oct 2016 13:49:27 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-24 Message-ID: <99859679-b84b-49f2-861f-44c21d5cfc75@irsmsx102.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-24 02:47:27 +0000 commit: 7f01d9d471e5 previous commit: cca20d28f348 revision date: 2016-10-23 19:32:18 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.23% 0.75% 4.94% 5.68% :-) pybench 0.25% -0.02% 6.08% 5.12% :-( regex_v8 0.65% 0.05% -2.04% 10.58% :-) nbody 0.07% -0.10% 7.86% 5.03% :-) json_dump_v2 0.30% 0.37% 2.73% 10.44% :-| normal_startup 0.66% -0.69% -0.68% 2.31% :-) ssbench 0.16% 0.08% 2.17% 1.44% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-24/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Mon Oct 24 08:49:53 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 24 Oct 2016 13:49:53 +0100 Subject: [Python-checkins] BAD Benchmark Results for Python Default 2016-10-24 Message-ID: <09890b26-402e-427f-9d84-f8a285071e02@irsmsx102.ger.corp.intel.com> Results for project Python default, build date 2016-10-24 02:01:20 +0000 commit: 3e7da46aead3 previous commit: b6886ac88e28 revision date: 2016-10-23 19:33:12 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% -0.48% 5.78% 14.66% :-) pybench 0.10% 0.10% 5.44% 4.37% :-( regex_v8 3.82% -0.68% -4.09% 4.63% :-( nbody 0.12% -2.33% 2.07% 4.83% :-( json_dump_v2 0.33% 0.85% -10.85% 15.75% :-| normal_startup 0.76% -1.18% 0.62% 6.57% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/bad-benchmark-results-for-python-default-2016-10-24/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Mon Oct 24 10:32:32 2016 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 24 Oct 2016 14:32:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzU4MzA6?= =?utf-8?q?__Remove_old_comment=2E__Add_empty_slots=2E?= Message-ID: <20161024143229.32885.85440.FE1C2C1C@psf.io> https://hg.python.org/cpython/rev/ee476248a74a changeset: 104677:ee476248a74a branch: 3.6 parent: 104674:081329cca21f user: Raymond Hettinger date: Mon Oct 24 07:31:55 2016 -0700 summary: Issue #5830: Remove old comment. Add empty slots. files: Lib/sched.py | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -23,11 +23,6 @@ has another way to reference private data (besides global variables). """ -# XXX The timefunc and delayfunc should have been defined as methods -# XXX so you can define new kinds of schedulers using subclassing -# XXX instead of having to define a module or class just to hold -# XXX the global state of your particular time and delay functions. - import time import heapq from collections import namedtuple @@ -40,6 +35,7 @@ __all__ = ["scheduler"] class Event(namedtuple('Event', 'time, priority, action, argument, kwargs')): + __slots__ = [] def __eq__(s, o): return (s.time, s.priority) == (o.time, o.priority) def __lt__(s, o): return (s.time, s.priority) < (o.time, o.priority) def __le__(s, o): return (s.time, s.priority) <= (o.time, o.priority) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 10:32:32 2016 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 24 Oct 2016 14:32:32 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20161024143230.12089.40571.3EF7715C@psf.io> https://hg.python.org/cpython/rev/aeeeb2b4f4eb changeset: 104678:aeeeb2b4f4eb parent: 104676:c5f40d0b7faa parent: 104677:ee476248a74a user: Raymond Hettinger date: Mon Oct 24 07:32:23 2016 -0700 summary: merge files: Lib/sched.py | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -23,11 +23,6 @@ has another way to reference private data (besides global variables). """ -# XXX The timefunc and delayfunc should have been defined as methods -# XXX so you can define new kinds of schedulers using subclassing -# XXX instead of having to define a module or class just to hold -# XXX the global state of your particular time and delay functions. - import time import heapq from collections import namedtuple @@ -40,6 +35,7 @@ __all__ = ["scheduler"] class Event(namedtuple('Event', 'time, priority, action, argument, kwargs')): + __slots__ = [] def __eq__(s, o): return (s.time, s.priority) == (o.time, o.priority) def __lt__(s, o): return (s.time, s.priority) < (o.time, o.priority) def __le__(s, o): return (s.time, s.priority) <= (o.time, o.priority) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 16:50:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 20:50:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2325464=3A_Fixed_HList=2Eheader=5Fexists=28=29_in_tkint?= =?utf-8?q?er=2Etix_module_by_addin?= Message-ID: <20161024205021.16631.98289.018E450E@psf.io> https://hg.python.org/cpython/rev/523aecdb8d5f changeset: 104681:523aecdb8d5f branch: 3.6 parent: 104677:ee476248a74a parent: 104680:e928afbcc18a user: Serhiy Storchaka date: Mon Oct 24 23:49:10 2016 +0300 summary: Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin a workaround to Tix library bug. files: Lib/tkinter/tix.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py --- a/Lib/tkinter/tix.py +++ b/Lib/tkinter/tix.py @@ -926,7 +926,11 @@ return self.tk.call(self._w, 'header', 'cget', col, opt) def header_exists(self, col): - return self.tk.call(self._w, 'header', 'exists', col) + # A workaround to Tix library bug (issue #25464). + # The documented command is "exists", but only erroneous "exist" is + # accepted. + return self.tk.getboolean(self.tk.call(self._w, 'header', 'exist', col)) + header_exist = header_exists def header_delete(self, col): self.tk.call(self._w, 'header', 'delete', col) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin + a workaround to Tix library bug. + - Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. - Issue #25953: re.sub() now raises an error for invalid numerical group -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 16:50:20 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 20:50:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI1NDY0?= =?utf-8?q?=3A_Fixed_HList=2Eheader=5Fexists=28=29_in_Tix_module_by_adding?= Message-ID: <20161024205020.39011.45345.FE7639A3@psf.io> https://hg.python.org/cpython/rev/f57078cf5f13 changeset: 104679:f57078cf5f13 branch: 2.7 parent: 104670:1a7452e0d852 user: Serhiy Storchaka date: Mon Oct 24 23:47:08 2016 +0300 summary: Issue #25464: Fixed HList.header_exists() in Tix module by adding a workaround to Tix library bug. files: Lib/lib-tk/Tix.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/lib-tk/Tix.py b/Lib/lib-tk/Tix.py --- a/Lib/lib-tk/Tix.py +++ b/Lib/lib-tk/Tix.py @@ -928,7 +928,11 @@ return self.tk.call(self._w, 'header', 'cget', col, opt) def header_exists(self, col): - return self.tk.call(self._w, 'header', 'exists', col) + # A workaround to Tix library bug (issue #25464). + # The documented command is "exists", but only erroneous "exist" is + # accepted. + return self.tk.getboolean(self.tk.call(self._w, 'header', 'exist', col)) + header_exist = header_exists def header_delete(self, col): self.tk.call(self._w, 'header', 'delete', col) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,9 @@ Library ------- +- Issue #25464: Fixed HList.header_exists() in Tix module by adding + a workaround to Tix library bug. + - Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. - Issue #28480: Fix error building _sqlite3 module when multithreading is -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 16:50:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 20:50:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2325464=3A_Fixed_HList=2Eheader=5Fexists=28=29_in?= =?utf-8?q?_tkinter=2Etix_module_by_addin?= Message-ID: <20161024205021.9825.55731.4499608B@psf.io> https://hg.python.org/cpython/rev/5b33829badcc changeset: 104682:5b33829badcc parent: 104678:aeeeb2b4f4eb parent: 104681:523aecdb8d5f user: Serhiy Storchaka date: Mon Oct 24 23:49:51 2016 +0300 summary: Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin a workaround to Tix library bug. files: Lib/tkinter/tix.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py --- a/Lib/tkinter/tix.py +++ b/Lib/tkinter/tix.py @@ -926,7 +926,11 @@ return self.tk.call(self._w, 'header', 'cget', col, opt) def header_exists(self, col): - return self.tk.call(self._w, 'header', 'exists', col) + # A workaround to Tix library bug (issue #25464). + # The documented command is "exists", but only erroneous "exist" is + # accepted. + return self.tk.getboolean(self.tk.call(self._w, 'header', 'exist', col)) + header_exist = header_exists def header_delete(self, col): self.tk.call(self._w, 'header', 'delete', col) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,9 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). +- Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin + a workaround to Tix library bug. + - Issue #28488: shutil.make_archive() no longer adds entry "./" to ZIP archive. - Issue #25953: re.sub() now raises an error for invalid numerical group -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 24 16:50:22 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 24 Oct 2016 20:50:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI1NDY0?= =?utf-8?q?=3A_Fixed_HList=2Eheader=5Fexists=28=29_in_tkinter=2Etix_module?= =?utf-8?q?_by_addin?= Message-ID: <20161024205020.25195.95187.C31FE448@psf.io> https://hg.python.org/cpython/rev/e928afbcc18a changeset: 104680:e928afbcc18a branch: 3.5 parent: 104671:bb9cea3c3e2c user: Serhiy Storchaka date: Mon Oct 24 23:47:28 2016 +0300 summary: Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin a workaround to Tix library bug. files: Lib/tkinter/tix.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py --- a/Lib/tkinter/tix.py +++ b/Lib/tkinter/tix.py @@ -929,7 +929,11 @@ return self.tk.call(self._w, 'header', 'cget', col, opt) def header_exists(self, col): - return self.tk.call(self._w, 'header', 'exists', col) + # A workaround to Tix library bug (issue #25464). + # The documented command is "exists", but only erroneous "exist" is + # accepted. + return self.tk.getboolean(self.tk.call(self._w, 'header', 'exist', col)) + header_exist = header_exists def header_delete(self, col): self.tk.call(self._w, 'header', 'delete', col) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,9 @@ Library ------- +- Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin + a workaround to Tix library bug. + - Issue #28488: shutil.make_archive() no longer add entry "./" to ZIP archive. - Issue #24452: Make webbrowser support Chrome on Mac OS X. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:00:36 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Oct 2016 06:00:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy42ICgjMjg1MjUp?= Message-ID: <20161025060036.68647.54625.8A111244@psf.io> https://hg.python.org/cpython/rev/ffaf02ec9d8b changeset: 104685:ffaf02ec9d8b parent: 104682:5b33829badcc parent: 104684:f9a04afaeece user: Benjamin Peterson date: Mon Oct 24 23:00:27 2016 -0700 summary: merge 3.6 (#28525) files: Doc/library/gc.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -38,7 +38,7 @@ Returns true if automatic collection is enabled. -.. function:: collect(generations=2) +.. function:: collect(generation=2) With no arguments, run a full collection. The optional argument *generation* may be an integer specifying which generation to collect (from 0 to 2). A -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:00:36 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Oct 2016 06:00:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_fix_name_of_ke?= =?utf-8?q?yword_parameter_to_gc=2Ecollect=28=29_=28closes_=2328525=29?= Message-ID: <20161025060036.38856.68329.3205707A@psf.io> https://hg.python.org/cpython/rev/05b5e1aaedc5 changeset: 104683:05b5e1aaedc5 branch: 3.5 parent: 104680:e928afbcc18a user: Benjamin Peterson date: Mon Oct 24 23:00:03 2016 -0700 summary: fix name of keyword parameter to gc.collect() (closes #28525) Patch from vierja. files: Doc/library/gc.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -38,7 +38,7 @@ Returns true if automatic collection is enabled. -.. function:: collect(generations=2) +.. function:: collect(generation=2) With no arguments, run a full collection. The optional argument *generation* may be an integer specifying which generation to collect (from 0 to 2). A -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:00:36 2016 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Oct 2016 06:00:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_merge_3=2E5_=28=2328525=29?= Message-ID: <20161025060036.68588.73826.5644DBA6@psf.io> https://hg.python.org/cpython/rev/f9a04afaeece changeset: 104684:f9a04afaeece branch: 3.6 parent: 104681:523aecdb8d5f parent: 104683:05b5e1aaedc5 user: Benjamin Peterson date: Mon Oct 24 23:00:18 2016 -0700 summary: merge 3.5 (#28525) files: Doc/library/gc.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -38,7 +38,7 @@ Returns true if automatic collection is enabled. -.. function:: collect(generations=2) +.. function:: collect(generation=2) With no arguments, run a full collection. The optional argument *generation* may be an integer specifying which generation to collect (from 0 to 2). A -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:42:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 06:42:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTE3?= =?utf-8?q?=3A_Fixed_of-by-one_error_in_the_peephole_optimizer_that_caused?= Message-ID: <20161025064228.11996.21957.5D4B0AA6@psf.io> https://hg.python.org/cpython/rev/5784cc37b5f4 changeset: 104686:5784cc37b5f4 branch: 3.6 parent: 104684:f9a04afaeece user: Serhiy Storchaka date: Tue Oct 25 09:30:43 2016 +0300 summary: Issue #28517: Fixed of-by-one error in the peephole optimizer that caused keeping unreachable code. files: Misc/NEWS | 3 + Python/importlib.h | 2298 ++++++------ Python/importlib_external.h | 3917 +++++++++++----------- Python/peephole.c | 4 +- 4 files changed, 3111 insertions(+), 3111 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28517: Fixed of-by-one error in the peephole optimizer that caused + keeping unreachable code. + - Issue #28214: Improved exception reporting for problematic __set_name__ attributes. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/importlib_external.h b/Python/importlib_external.h --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -459,1979 +459,1978 @@ 101,85,1,0,0,115,20,0,0,0,0,7,12,1,4,1, 16,1,26,1,4,1,2,1,12,1,18,1,18,1,114,95, 0,0,0,99,1,0,0,0,0,0,0,0,1,0,0,0, - 11,0,0,0,67,0,0,0,115,74,0,0,0,124,0,106, + 11,0,0,0,67,0,0,0,115,72,0,0,0,124,0,106, 0,116,1,116,2,131,1,131,1,114,46,121,8,116,3,124, 0,131,1,83,0,4,0,116,4,107,10,114,42,1,0,1, - 0,1,0,89,0,113,70,88,0,110,24,124,0,106,0,116, - 1,116,5,131,1,131,1,114,66,124,0,83,0,110,4,100, - 0,83,0,100,0,83,0,41,1,78,41,6,218,8,101,110, - 100,115,119,105,116,104,218,5,116,117,112,108,101,114,88,0, - 0,0,114,83,0,0,0,114,70,0,0,0,114,78,0,0, - 0,41,1,218,8,102,105,108,101,110,97,109,101,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,11,95,103, - 101,116,95,99,97,99,104,101,100,104,1,0,0,115,16,0, - 0,0,0,1,14,1,2,1,8,1,14,1,8,1,14,1, - 6,2,114,99,0,0,0,99,1,0,0,0,0,0,0,0, - 2,0,0,0,11,0,0,0,67,0,0,0,115,52,0,0, - 0,121,14,116,0,124,0,131,1,106,1,125,1,87,0,110, - 24,4,0,116,2,107,10,114,38,1,0,1,0,1,0,100, - 1,125,1,89,0,110,2,88,0,124,1,100,2,79,0,125, - 1,124,1,83,0,41,3,122,51,67,97,108,99,117,108,97, - 116,101,32,116,104,101,32,109,111,100,101,32,112,101,114,109, - 105,115,115,105,111,110,115,32,102,111,114,32,97,32,98,121, - 116,101,99,111,100,101,32,102,105,108,101,46,105,182,1,0, - 0,233,128,0,0,0,41,3,114,41,0,0,0,114,43,0, - 0,0,114,42,0,0,0,41,2,114,37,0,0,0,114,44, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,10,95,99,97,108,99,95,109,111,100,101,116,1, - 0,0,115,12,0,0,0,0,2,2,1,14,1,14,1,10, - 3,8,1,114,101,0,0,0,99,1,0,0,0,0,0,0, - 0,3,0,0,0,11,0,0,0,3,0,0,0,115,68,0, - 0,0,100,6,135,0,102,1,100,2,100,3,132,9,125,1, - 121,10,116,0,106,1,125,2,87,0,110,28,4,0,116,2, - 107,10,114,52,1,0,1,0,1,0,100,4,100,5,132,0, - 125,2,89,0,110,2,88,0,124,2,124,1,136,0,131,2, - 1,0,124,1,83,0,41,7,122,252,68,101,99,111,114,97, - 116,111,114,32,116,111,32,118,101,114,105,102,121,32,116,104, - 97,116,32,116,104,101,32,109,111,100,117,108,101,32,98,101, - 105,110,103,32,114,101,113,117,101,115,116,101,100,32,109,97, - 116,99,104,101,115,32,116,104,101,32,111,110,101,32,116,104, - 101,10,32,32,32,32,108,111,97,100,101,114,32,99,97,110, - 32,104,97,110,100,108,101,46,10,10,32,32,32,32,84,104, - 101,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116, - 32,40,115,101,108,102,41,32,109,117,115,116,32,100,101,102, - 105,110,101,32,95,110,97,109,101,32,119,104,105,99,104,32, - 116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109, - 101,110,116,32,105,115,10,32,32,32,32,99,111,109,112,97, - 114,101,100,32,97,103,97,105,110,115,116,46,32,73,102,32, - 116,104,101,32,99,111,109,112,97,114,105,115,111,110,32,102, - 97,105,108,115,32,116,104,101,110,32,73,109,112,111,114,116, - 69,114,114,111,114,32,105,115,32,114,97,105,115,101,100,46, - 10,10,32,32,32,32,78,99,2,0,0,0,0,0,0,0, - 4,0,0,0,4,0,0,0,31,0,0,0,115,66,0,0, - 0,124,1,100,0,107,8,114,16,124,0,106,0,125,1,110, - 32,124,0,106,0,124,1,107,3,114,48,116,1,100,1,124, - 0,106,0,124,1,102,2,22,0,124,1,100,2,141,2,130, - 1,136,0,124,0,124,1,102,2,124,2,158,2,124,3,142, - 1,83,0,41,3,78,122,30,108,111,97,100,101,114,32,102, - 111,114,32,37,115,32,99,97,110,110,111,116,32,104,97,110, - 100,108,101,32,37,115,41,1,218,4,110,97,109,101,41,2, - 114,102,0,0,0,218,11,73,109,112,111,114,116,69,114,114, - 111,114,41,4,218,4,115,101,108,102,114,102,0,0,0,218, - 4,97,114,103,115,90,6,107,119,97,114,103,115,41,1,218, - 6,109,101,116,104,111,100,114,4,0,0,0,114,6,0,0, - 0,218,19,95,99,104,101,99,107,95,110,97,109,101,95,119, - 114,97,112,112,101,114,136,1,0,0,115,12,0,0,0,0, - 1,8,1,8,1,10,1,4,1,18,1,122,40,95,99,104, - 101,99,107,95,110,97,109,101,46,60,108,111,99,97,108,115, - 62,46,95,99,104,101,99,107,95,110,97,109,101,95,119,114, - 97,112,112,101,114,99,2,0,0,0,0,0,0,0,3,0, - 0,0,7,0,0,0,83,0,0,0,115,60,0,0,0,120, - 40,100,5,68,0,93,32,125,2,116,0,124,1,124,2,131, - 2,114,6,116,1,124,0,124,2,116,2,124,1,124,2,131, - 2,131,3,1,0,113,6,87,0,124,0,106,3,106,4,124, - 1,106,3,131,1,1,0,100,0,83,0,41,6,78,218,10, - 95,95,109,111,100,117,108,101,95,95,218,8,95,95,110,97, - 109,101,95,95,218,12,95,95,113,117,97,108,110,97,109,101, - 95,95,218,7,95,95,100,111,99,95,95,41,4,114,108,0, - 0,0,114,109,0,0,0,114,110,0,0,0,114,111,0,0, - 0,41,5,218,7,104,97,115,97,116,116,114,218,7,115,101, - 116,97,116,116,114,218,7,103,101,116,97,116,116,114,218,8, - 95,95,100,105,99,116,95,95,218,6,117,112,100,97,116,101, - 41,3,90,3,110,101,119,90,3,111,108,100,114,55,0,0, + 0,1,0,89,0,113,68,88,0,110,22,124,0,106,0,116, + 1,116,5,131,1,131,1,114,64,124,0,83,0,100,0,83, + 0,100,0,83,0,41,1,78,41,6,218,8,101,110,100,115, + 119,105,116,104,218,5,116,117,112,108,101,114,88,0,0,0, + 114,83,0,0,0,114,70,0,0,0,114,78,0,0,0,41, + 1,218,8,102,105,108,101,110,97,109,101,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,11,95,103,101,116, + 95,99,97,99,104,101,100,104,1,0,0,115,16,0,0,0, + 0,1,14,1,2,1,8,1,14,1,8,1,14,1,4,2, + 114,99,0,0,0,99,1,0,0,0,0,0,0,0,2,0, + 0,0,11,0,0,0,67,0,0,0,115,52,0,0,0,121, + 14,116,0,124,0,131,1,106,1,125,1,87,0,110,24,4, + 0,116,2,107,10,114,38,1,0,1,0,1,0,100,1,125, + 1,89,0,110,2,88,0,124,1,100,2,79,0,125,1,124, + 1,83,0,41,3,122,51,67,97,108,99,117,108,97,116,101, + 32,116,104,101,32,109,111,100,101,32,112,101,114,109,105,115, + 115,105,111,110,115,32,102,111,114,32,97,32,98,121,116,101, + 99,111,100,101,32,102,105,108,101,46,105,182,1,0,0,233, + 128,0,0,0,41,3,114,41,0,0,0,114,43,0,0,0, + 114,42,0,0,0,41,2,114,37,0,0,0,114,44,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,5,95,119,114,97,112,147,1,0,0,115,8,0,0,0, - 0,1,10,1,10,1,22,1,122,26,95,99,104,101,99,107, - 95,110,97,109,101,46,60,108,111,99,97,108,115,62,46,95, - 119,114,97,112,41,1,78,41,3,218,10,95,98,111,111,116, - 115,116,114,97,112,114,117,0,0,0,218,9,78,97,109,101, - 69,114,114,111,114,41,3,114,106,0,0,0,114,107,0,0, - 0,114,117,0,0,0,114,4,0,0,0,41,1,114,106,0, - 0,0,114,6,0,0,0,218,11,95,99,104,101,99,107,95, - 110,97,109,101,128,1,0,0,115,14,0,0,0,0,8,14, - 7,2,1,10,1,14,2,14,5,10,1,114,120,0,0,0, - 99,2,0,0,0,0,0,0,0,5,0,0,0,4,0,0, - 0,67,0,0,0,115,60,0,0,0,124,0,106,0,124,1, - 131,1,92,2,125,2,125,3,124,2,100,1,107,8,114,56, - 116,1,124,3,131,1,114,56,100,2,125,4,116,2,106,3, - 124,4,106,4,124,3,100,3,25,0,131,1,116,5,131,2, - 1,0,124,2,83,0,41,4,122,155,84,114,121,32,116,111, - 32,102,105,110,100,32,97,32,108,111,97,100,101,114,32,102, - 111,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100, - 32,109,111,100,117,108,101,32,98,121,32,100,101,108,101,103, - 97,116,105,110,103,32,116,111,10,32,32,32,32,115,101,108, - 102,46,102,105,110,100,95,108,111,97,100,101,114,40,41,46, - 10,10,32,32,32,32,84,104,105,115,32,109,101,116,104,111, - 100,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32, - 105,110,32,102,97,118,111,114,32,111,102,32,102,105,110,100, - 101,114,46,102,105,110,100,95,115,112,101,99,40,41,46,10, - 10,32,32,32,32,78,122,44,78,111,116,32,105,109,112,111, - 114,116,105,110,103,32,100,105,114,101,99,116,111,114,121,32, - 123,125,58,32,109,105,115,115,105,110,103,32,95,95,105,110, - 105,116,95,95,114,62,0,0,0,41,6,218,11,102,105,110, - 100,95,108,111,97,100,101,114,114,33,0,0,0,114,63,0, - 0,0,114,64,0,0,0,114,50,0,0,0,218,13,73,109, - 112,111,114,116,87,97,114,110,105,110,103,41,5,114,104,0, - 0,0,218,8,102,117,108,108,110,97,109,101,218,6,108,111, - 97,100,101,114,218,8,112,111,114,116,105,111,110,115,218,3, - 109,115,103,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,17,95,102,105,110,100,95,109,111,100,117,108,101, - 95,115,104,105,109,156,1,0,0,115,10,0,0,0,0,10, - 14,1,16,1,4,1,22,1,114,127,0,0,0,99,4,0, - 0,0,0,0,0,0,11,0,0,0,22,0,0,0,67,0, - 0,0,115,136,1,0,0,105,0,125,4,124,2,100,1,107, - 9,114,22,124,2,124,4,100,2,60,0,110,4,100,3,125, - 2,124,3,100,1,107,9,114,42,124,3,124,4,100,4,60, - 0,124,0,100,1,100,5,133,2,25,0,125,5,124,0,100, - 5,100,6,133,2,25,0,125,6,124,0,100,6,100,7,133, - 2,25,0,125,7,124,5,116,0,107,3,114,124,100,8,106, - 1,124,2,124,5,131,2,125,8,116,2,106,3,100,9,124, - 8,131,2,1,0,116,4,124,8,102,1,124,4,142,1,130, - 1,110,86,116,5,124,6,131,1,100,5,107,3,114,168,100, - 10,106,1,124,2,131,1,125,8,116,2,106,3,100,9,124, - 8,131,2,1,0,116,6,124,8,131,1,130,1,110,42,116, - 5,124,7,131,1,100,5,107,3,114,210,100,11,106,1,124, - 2,131,1,125,8,116,2,106,3,100,9,124,8,131,2,1, - 0,116,6,124,8,131,1,130,1,124,1,100,1,107,9,144, - 1,114,124,121,16,116,7,124,1,100,12,25,0,131,1,125, - 9,87,0,110,22,4,0,116,8,107,10,144,1,114,2,1, - 0,1,0,1,0,89,0,110,50,88,0,116,9,124,6,131, - 1,124,9,107,3,144,1,114,52,100,13,106,1,124,2,131, + 218,10,95,99,97,108,99,95,109,111,100,101,116,1,0,0, + 115,12,0,0,0,0,2,2,1,14,1,14,1,10,3,8, + 1,114,101,0,0,0,99,1,0,0,0,0,0,0,0,3, + 0,0,0,11,0,0,0,3,0,0,0,115,68,0,0,0, + 100,6,135,0,102,1,100,2,100,3,132,9,125,1,121,10, + 116,0,106,1,125,2,87,0,110,28,4,0,116,2,107,10, + 114,52,1,0,1,0,1,0,100,4,100,5,132,0,125,2, + 89,0,110,2,88,0,124,2,124,1,136,0,131,2,1,0, + 124,1,83,0,41,7,122,252,68,101,99,111,114,97,116,111, + 114,32,116,111,32,118,101,114,105,102,121,32,116,104,97,116, + 32,116,104,101,32,109,111,100,117,108,101,32,98,101,105,110, + 103,32,114,101,113,117,101,115,116,101,100,32,109,97,116,99, + 104,101,115,32,116,104,101,32,111,110,101,32,116,104,101,10, + 32,32,32,32,108,111,97,100,101,114,32,99,97,110,32,104, + 97,110,100,108,101,46,10,10,32,32,32,32,84,104,101,32, + 102,105,114,115,116,32,97,114,103,117,109,101,110,116,32,40, + 115,101,108,102,41,32,109,117,115,116,32,100,101,102,105,110, + 101,32,95,110,97,109,101,32,119,104,105,99,104,32,116,104, + 101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110, + 116,32,105,115,10,32,32,32,32,99,111,109,112,97,114,101, + 100,32,97,103,97,105,110,115,116,46,32,73,102,32,116,104, + 101,32,99,111,109,112,97,114,105,115,111,110,32,102,97,105, + 108,115,32,116,104,101,110,32,73,109,112,111,114,116,69,114, + 114,111,114,32,105,115,32,114,97,105,115,101,100,46,10,10, + 32,32,32,32,78,99,2,0,0,0,0,0,0,0,4,0, + 0,0,4,0,0,0,31,0,0,0,115,66,0,0,0,124, + 1,100,0,107,8,114,16,124,0,106,0,125,1,110,32,124, + 0,106,0,124,1,107,3,114,48,116,1,100,1,124,0,106, + 0,124,1,102,2,22,0,124,1,100,2,141,2,130,1,136, + 0,124,0,124,1,102,2,124,2,158,2,124,3,142,1,83, + 0,41,3,78,122,30,108,111,97,100,101,114,32,102,111,114, + 32,37,115,32,99,97,110,110,111,116,32,104,97,110,100,108, + 101,32,37,115,41,1,218,4,110,97,109,101,41,2,114,102, + 0,0,0,218,11,73,109,112,111,114,116,69,114,114,111,114, + 41,4,218,4,115,101,108,102,114,102,0,0,0,218,4,97, + 114,103,115,90,6,107,119,97,114,103,115,41,1,218,6,109, + 101,116,104,111,100,114,4,0,0,0,114,6,0,0,0,218, + 19,95,99,104,101,99,107,95,110,97,109,101,95,119,114,97, + 112,112,101,114,136,1,0,0,115,12,0,0,0,0,1,8, + 1,8,1,10,1,4,1,18,1,122,40,95,99,104,101,99, + 107,95,110,97,109,101,46,60,108,111,99,97,108,115,62,46, + 95,99,104,101,99,107,95,110,97,109,101,95,119,114,97,112, + 112,101,114,99,2,0,0,0,0,0,0,0,3,0,0,0, + 7,0,0,0,83,0,0,0,115,60,0,0,0,120,40,100, + 5,68,0,93,32,125,2,116,0,124,1,124,2,131,2,114, + 6,116,1,124,0,124,2,116,2,124,1,124,2,131,2,131, + 3,1,0,113,6,87,0,124,0,106,3,106,4,124,1,106, + 3,131,1,1,0,100,0,83,0,41,6,78,218,10,95,95, + 109,111,100,117,108,101,95,95,218,8,95,95,110,97,109,101, + 95,95,218,12,95,95,113,117,97,108,110,97,109,101,95,95, + 218,7,95,95,100,111,99,95,95,41,4,114,108,0,0,0, + 114,109,0,0,0,114,110,0,0,0,114,111,0,0,0,41, + 5,218,7,104,97,115,97,116,116,114,218,7,115,101,116,97, + 116,116,114,218,7,103,101,116,97,116,116,114,218,8,95,95, + 100,105,99,116,95,95,218,6,117,112,100,97,116,101,41,3, + 90,3,110,101,119,90,3,111,108,100,114,55,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,5, + 95,119,114,97,112,147,1,0,0,115,8,0,0,0,0,1, + 10,1,10,1,22,1,122,26,95,99,104,101,99,107,95,110, + 97,109,101,46,60,108,111,99,97,108,115,62,46,95,119,114, + 97,112,41,1,78,41,3,218,10,95,98,111,111,116,115,116, + 114,97,112,114,117,0,0,0,218,9,78,97,109,101,69,114, + 114,111,114,41,3,114,106,0,0,0,114,107,0,0,0,114, + 117,0,0,0,114,4,0,0,0,41,1,114,106,0,0,0, + 114,6,0,0,0,218,11,95,99,104,101,99,107,95,110,97, + 109,101,128,1,0,0,115,14,0,0,0,0,8,14,7,2, + 1,10,1,14,2,14,5,10,1,114,120,0,0,0,99,2, + 0,0,0,0,0,0,0,5,0,0,0,4,0,0,0,67, + 0,0,0,115,60,0,0,0,124,0,106,0,124,1,131,1, + 92,2,125,2,125,3,124,2,100,1,107,8,114,56,116,1, + 124,3,131,1,114,56,100,2,125,4,116,2,106,3,124,4, + 106,4,124,3,100,3,25,0,131,1,116,5,131,2,1,0, + 124,2,83,0,41,4,122,155,84,114,121,32,116,111,32,102, + 105,110,100,32,97,32,108,111,97,100,101,114,32,102,111,114, + 32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,109, + 111,100,117,108,101,32,98,121,32,100,101,108,101,103,97,116, + 105,110,103,32,116,111,10,32,32,32,32,115,101,108,102,46, + 102,105,110,100,95,108,111,97,100,101,114,40,41,46,10,10, + 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32, + 105,115,32,100,101,112,114,101,99,97,116,101,100,32,105,110, + 32,102,97,118,111,114,32,111,102,32,102,105,110,100,101,114, + 46,102,105,110,100,95,115,112,101,99,40,41,46,10,10,32, + 32,32,32,78,122,44,78,111,116,32,105,109,112,111,114,116, + 105,110,103,32,100,105,114,101,99,116,111,114,121,32,123,125, + 58,32,109,105,115,115,105,110,103,32,95,95,105,110,105,116, + 95,95,114,62,0,0,0,41,6,218,11,102,105,110,100,95, + 108,111,97,100,101,114,114,33,0,0,0,114,63,0,0,0, + 114,64,0,0,0,114,50,0,0,0,218,13,73,109,112,111, + 114,116,87,97,114,110,105,110,103,41,5,114,104,0,0,0, + 218,8,102,117,108,108,110,97,109,101,218,6,108,111,97,100, + 101,114,218,8,112,111,114,116,105,111,110,115,218,3,109,115, + 103,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,17,95,102,105,110,100,95,109,111,100,117,108,101,95,115, + 104,105,109,156,1,0,0,115,10,0,0,0,0,10,14,1, + 16,1,4,1,22,1,114,127,0,0,0,99,4,0,0,0, + 0,0,0,0,11,0,0,0,22,0,0,0,67,0,0,0, + 115,136,1,0,0,105,0,125,4,124,2,100,1,107,9,114, + 22,124,2,124,4,100,2,60,0,110,4,100,3,125,2,124, + 3,100,1,107,9,114,42,124,3,124,4,100,4,60,0,124, + 0,100,1,100,5,133,2,25,0,125,5,124,0,100,5,100, + 6,133,2,25,0,125,6,124,0,100,6,100,7,133,2,25, + 0,125,7,124,5,116,0,107,3,114,124,100,8,106,1,124, + 2,124,5,131,2,125,8,116,2,106,3,100,9,124,8,131, + 2,1,0,116,4,124,8,102,1,124,4,142,1,130,1,110, + 86,116,5,124,6,131,1,100,5,107,3,114,168,100,10,106, + 1,124,2,131,1,125,8,116,2,106,3,100,9,124,8,131, + 2,1,0,116,6,124,8,131,1,130,1,110,42,116,5,124, + 7,131,1,100,5,107,3,114,210,100,11,106,1,124,2,131, 1,125,8,116,2,106,3,100,9,124,8,131,2,1,0,116, - 4,124,8,102,1,124,4,142,1,130,1,121,16,124,1,100, - 14,25,0,100,15,64,0,125,10,87,0,110,22,4,0,116, - 8,107,10,144,1,114,90,1,0,1,0,1,0,89,0,110, - 34,88,0,116,9,124,7,131,1,124,10,107,3,144,1,114, - 124,116,4,100,13,106,1,124,2,131,1,102,1,124,4,142, - 1,130,1,124,0,100,7,100,1,133,2,25,0,83,0,41, - 16,97,122,1,0,0,86,97,108,105,100,97,116,101,32,116, - 104,101,32,104,101,97,100,101,114,32,111,102,32,116,104,101, - 32,112,97,115,115,101,100,45,105,110,32,98,121,116,101,99, - 111,100,101,32,97,103,97,105,110,115,116,32,115,111,117,114, - 99,101,95,115,116,97,116,115,32,40,105,102,10,32,32,32, - 32,103,105,118,101,110,41,32,97,110,100,32,114,101,116,117, - 114,110,105,110,103,32,116,104,101,32,98,121,116,101,99,111, - 100,101,32,116,104,97,116,32,99,97,110,32,98,101,32,99, - 111,109,112,105,108,101,100,32,98,121,32,99,111,109,112,105, - 108,101,40,41,46,10,10,32,32,32,32,65,108,108,32,111, - 116,104,101,114,32,97,114,103,117,109,101,110,116,115,32,97, - 114,101,32,117,115,101,100,32,116,111,32,101,110,104,97,110, - 99,101,32,101,114,114,111,114,32,114,101,112,111,114,116,105, - 110,103,46,10,10,32,32,32,32,73,109,112,111,114,116,69, - 114,114,111,114,32,105,115,32,114,97,105,115,101,100,32,119, - 104,101,110,32,116,104,101,32,109,97,103,105,99,32,110,117, - 109,98,101,114,32,105,115,32,105,110,99,111,114,114,101,99, - 116,32,111,114,32,116,104,101,32,98,121,116,101,99,111,100, - 101,32,105,115,10,32,32,32,32,102,111,117,110,100,32,116, - 111,32,98,101,32,115,116,97,108,101,46,32,69,79,70,69, - 114,114,111,114,32,105,115,32,114,97,105,115,101,100,32,119, - 104,101,110,32,116,104,101,32,100,97,116,97,32,105,115,32, - 102,111,117,110,100,32,116,111,32,98,101,10,32,32,32,32, - 116,114,117,110,99,97,116,101,100,46,10,10,32,32,32,32, - 78,114,102,0,0,0,122,10,60,98,121,116,101,99,111,100, - 101,62,114,37,0,0,0,114,14,0,0,0,233,8,0,0, - 0,233,12,0,0,0,122,30,98,97,100,32,109,97,103,105, - 99,32,110,117,109,98,101,114,32,105,110,32,123,33,114,125, - 58,32,123,33,114,125,122,2,123,125,122,43,114,101,97,99, - 104,101,100,32,69,79,70,32,119,104,105,108,101,32,114,101, - 97,100,105,110,103,32,116,105,109,101,115,116,97,109,112,32, - 105,110,32,123,33,114,125,122,48,114,101,97,99,104,101,100, - 32,69,79,70,32,119,104,105,108,101,32,114,101,97,100,105, - 110,103,32,115,105,122,101,32,111,102,32,115,111,117,114,99, - 101,32,105,110,32,123,33,114,125,218,5,109,116,105,109,101, - 122,26,98,121,116,101,99,111,100,101,32,105,115,32,115,116, - 97,108,101,32,102,111,114,32,123,33,114,125,218,4,115,105, - 122,101,108,3,0,0,0,255,127,255,127,3,0,41,10,218, - 12,77,65,71,73,67,95,78,85,77,66,69,82,114,50,0, - 0,0,114,118,0,0,0,218,16,95,118,101,114,98,111,115, - 101,95,109,101,115,115,97,103,101,114,103,0,0,0,114,33, - 0,0,0,218,8,69,79,70,69,114,114,111,114,114,16,0, - 0,0,218,8,75,101,121,69,114,114,111,114,114,21,0,0, - 0,41,11,114,56,0,0,0,218,12,115,111,117,114,99,101, - 95,115,116,97,116,115,114,102,0,0,0,114,37,0,0,0, - 90,11,101,120,99,95,100,101,116,97,105,108,115,90,5,109, - 97,103,105,99,90,13,114,97,119,95,116,105,109,101,115,116, - 97,109,112,90,8,114,97,119,95,115,105,122,101,114,79,0, - 0,0,218,12,115,111,117,114,99,101,95,109,116,105,109,101, - 218,11,115,111,117,114,99,101,95,115,105,122,101,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,25,95,118, - 97,108,105,100,97,116,101,95,98,121,116,101,99,111,100,101, - 95,104,101,97,100,101,114,173,1,0,0,115,76,0,0,0, - 0,11,4,1,8,1,10,3,4,1,8,1,8,1,12,1, - 12,1,12,1,8,1,12,1,12,1,14,1,12,1,10,1, - 12,1,10,1,12,1,10,1,12,1,8,1,10,1,2,1, - 16,1,16,1,6,2,14,1,10,1,12,1,12,1,2,1, - 16,1,16,1,6,2,14,1,12,1,6,1,114,139,0,0, - 0,99,4,0,0,0,0,0,0,0,5,0,0,0,5,0, - 0,0,67,0,0,0,115,82,0,0,0,116,0,106,1,124, - 0,131,1,125,4,116,2,124,4,116,3,131,2,114,58,116, - 4,106,5,100,1,124,2,131,2,1,0,124,3,100,2,107, - 9,114,52,116,6,106,7,124,4,124,3,131,2,1,0,124, - 4,83,0,110,20,116,8,100,3,106,9,124,2,131,1,124, - 1,124,2,100,4,141,3,130,1,100,2,83,0,41,5,122, - 60,67,111,109,112,105,108,101,32,98,121,116,101,99,111,100, - 101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121, - 32,95,118,97,108,105,100,97,116,101,95,98,121,116,101,99, - 111,100,101,95,104,101,97,100,101,114,40,41,46,122,21,99, - 111,100,101,32,111,98,106,101,99,116,32,102,114,111,109,32, - 123,33,114,125,78,122,23,78,111,110,45,99,111,100,101,32, - 111,98,106,101,99,116,32,105,110,32,123,33,114,125,41,2, - 114,102,0,0,0,114,37,0,0,0,41,10,218,7,109,97, - 114,115,104,97,108,90,5,108,111,97,100,115,218,10,105,115, - 105,110,115,116,97,110,99,101,218,10,95,99,111,100,101,95, - 116,121,112,101,114,118,0,0,0,114,133,0,0,0,218,4, - 95,105,109,112,90,16,95,102,105,120,95,99,111,95,102,105, - 108,101,110,97,109,101,114,103,0,0,0,114,50,0,0,0, - 41,5,114,56,0,0,0,114,102,0,0,0,114,93,0,0, - 0,114,94,0,0,0,218,4,99,111,100,101,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,218,17,95,99,111, - 109,112,105,108,101,95,98,121,116,101,99,111,100,101,228,1, - 0,0,115,16,0,0,0,0,2,10,1,10,1,12,1,8, - 1,12,1,6,2,10,1,114,145,0,0,0,114,62,0,0, - 0,99,3,0,0,0,0,0,0,0,4,0,0,0,3,0, - 0,0,67,0,0,0,115,56,0,0,0,116,0,116,1,131, - 1,125,3,124,3,106,2,116,3,124,1,131,1,131,1,1, - 0,124,3,106,2,116,3,124,2,131,1,131,1,1,0,124, - 3,106,2,116,4,106,5,124,0,131,1,131,1,1,0,124, - 3,83,0,41,1,122,80,67,111,109,112,105,108,101,32,97, - 32,99,111,100,101,32,111,98,106,101,99,116,32,105,110,116, - 111,32,98,121,116,101,99,111,100,101,32,102,111,114,32,119, - 114,105,116,105,110,103,32,111,117,116,32,116,111,32,97,32, - 98,121,116,101,45,99,111,109,112,105,108,101,100,10,32,32, - 32,32,102,105,108,101,46,41,6,218,9,98,121,116,101,97, - 114,114,97,121,114,132,0,0,0,218,6,101,120,116,101,110, - 100,114,19,0,0,0,114,140,0,0,0,90,5,100,117,109, - 112,115,41,4,114,144,0,0,0,114,130,0,0,0,114,138, - 0,0,0,114,56,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,218,17,95,99,111,100,101,95,116, - 111,95,98,121,116,101,99,111,100,101,240,1,0,0,115,10, - 0,0,0,0,3,8,1,14,1,14,1,16,1,114,148,0, - 0,0,99,1,0,0,0,0,0,0,0,5,0,0,0,4, - 0,0,0,67,0,0,0,115,62,0,0,0,100,1,100,2, - 108,0,125,1,116,1,106,2,124,0,131,1,106,3,125,2, - 124,1,106,4,124,2,131,1,125,3,116,1,106,5,100,2, - 100,3,131,2,125,4,124,4,106,6,124,0,106,6,124,3, - 100,1,25,0,131,1,131,1,83,0,41,4,122,121,68,101, - 99,111,100,101,32,98,121,116,101,115,32,114,101,112,114,101, - 115,101,110,116,105,110,103,32,115,111,117,114,99,101,32,99, - 111,100,101,32,97,110,100,32,114,101,116,117,114,110,32,116, - 104,101,32,115,116,114,105,110,103,46,10,10,32,32,32,32, - 85,110,105,118,101,114,115,97,108,32,110,101,119,108,105,110, - 101,32,115,117,112,112,111,114,116,32,105,115,32,117,115,101, - 100,32,105,110,32,116,104,101,32,100,101,99,111,100,105,110, - 103,46,10,32,32,32,32,114,62,0,0,0,78,84,41,7, - 218,8,116,111,107,101,110,105,122,101,114,52,0,0,0,90, - 7,66,121,116,101,115,73,79,90,8,114,101,97,100,108,105, - 110,101,90,15,100,101,116,101,99,116,95,101,110,99,111,100, - 105,110,103,90,25,73,110,99,114,101,109,101,110,116,97,108, - 78,101,119,108,105,110,101,68,101,99,111,100,101,114,218,6, - 100,101,99,111,100,101,41,5,218,12,115,111,117,114,99,101, - 95,98,121,116,101,115,114,149,0,0,0,90,21,115,111,117, - 114,99,101,95,98,121,116,101,115,95,114,101,97,100,108,105, - 110,101,218,8,101,110,99,111,100,105,110,103,90,15,110,101, - 119,108,105,110,101,95,100,101,99,111,100,101,114,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,13,100,101, - 99,111,100,101,95,115,111,117,114,99,101,250,1,0,0,115, - 10,0,0,0,0,5,8,1,12,1,10,1,12,1,114,153, - 0,0,0,41,2,114,124,0,0,0,218,26,115,117,98,109, - 111,100,117,108,101,95,115,101,97,114,99,104,95,108,111,99, - 97,116,105,111,110,115,99,2,0,0,0,2,0,0,0,9, - 0,0,0,19,0,0,0,67,0,0,0,115,18,1,0,0, - 124,1,100,1,107,8,114,60,100,2,125,1,116,0,124,2, - 100,3,131,2,114,70,121,14,124,2,106,1,124,0,131,1, - 125,1,87,0,113,70,4,0,116,2,107,10,114,56,1,0, - 1,0,1,0,89,0,113,70,88,0,110,10,116,3,106,4, - 124,1,131,1,125,1,116,5,106,6,124,0,124,2,124,1, - 100,4,141,3,125,4,100,5,124,4,95,7,124,2,100,1, - 107,8,114,156,120,54,116,8,131,0,68,0,93,40,92,2, - 125,5,125,6,124,1,106,9,116,10,124,6,131,1,131,1, - 114,108,124,5,124,0,124,1,131,2,125,2,124,2,124,4, - 95,11,80,0,113,108,87,0,100,1,83,0,124,3,116,12, - 107,8,114,222,116,0,124,2,100,6,131,2,114,228,121,14, - 124,2,106,13,124,0,131,1,125,7,87,0,110,20,4,0, - 116,2,107,10,114,208,1,0,1,0,1,0,89,0,113,228, - 88,0,124,7,114,228,103,0,124,4,95,14,110,6,124,3, - 124,4,95,14,124,4,106,14,103,0,107,2,144,1,114,14, - 124,1,144,1,114,14,116,15,124,1,131,1,100,7,25,0, - 125,8,124,4,106,14,106,16,124,8,131,1,1,0,124,4, - 83,0,41,8,97,61,1,0,0,82,101,116,117,114,110,32, - 97,32,109,111,100,117,108,101,32,115,112,101,99,32,98,97, - 115,101,100,32,111,110,32,97,32,102,105,108,101,32,108,111, - 99,97,116,105,111,110,46,10,10,32,32,32,32,84,111,32, - 105,110,100,105,99,97,116,101,32,116,104,97,116,32,116,104, - 101,32,109,111,100,117,108,101,32,105,115,32,97,32,112,97, - 99,107,97,103,101,44,32,115,101,116,10,32,32,32,32,115, - 117,98,109,111,100,117,108,101,95,115,101,97,114,99,104,95, - 108,111,99,97,116,105,111,110,115,32,116,111,32,97,32,108, - 105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121, - 32,112,97,116,104,115,46,32,32,65,110,10,32,32,32,32, - 101,109,112,116,121,32,108,105,115,116,32,105,115,32,115,117, - 102,102,105,99,105,101,110,116,44,32,116,104,111,117,103,104, - 32,105,116,115,32,110,111,116,32,111,116,104,101,114,119,105, - 115,101,32,117,115,101,102,117,108,32,116,111,32,116,104,101, - 10,32,32,32,32,105,109,112,111,114,116,32,115,121,115,116, - 101,109,46,10,10,32,32,32,32,84,104,101,32,108,111,97, - 100,101,114,32,109,117,115,116,32,116,97,107,101,32,97,32, - 115,112,101,99,32,97,115,32,105,116,115,32,111,110,108,121, - 32,95,95,105,110,105,116,95,95,40,41,32,97,114,103,46, - 10,10,32,32,32,32,78,122,9,60,117,110,107,110,111,119, - 110,62,218,12,103,101,116,95,102,105,108,101,110,97,109,101, - 41,1,218,6,111,114,105,103,105,110,84,218,10,105,115,95, - 112,97,99,107,97,103,101,114,62,0,0,0,41,17,114,112, - 0,0,0,114,155,0,0,0,114,103,0,0,0,114,3,0, - 0,0,114,67,0,0,0,114,118,0,0,0,218,10,77,111, - 100,117,108,101,83,112,101,99,90,13,95,115,101,116,95,102, - 105,108,101,97,116,116,114,218,27,95,103,101,116,95,115,117, - 112,112,111,114,116,101,100,95,102,105,108,101,95,108,111,97, - 100,101,114,115,114,96,0,0,0,114,97,0,0,0,114,124, - 0,0,0,218,9,95,80,79,80,85,76,65,84,69,114,157, - 0,0,0,114,154,0,0,0,114,40,0,0,0,218,6,97, - 112,112,101,110,100,41,9,114,102,0,0,0,90,8,108,111, - 99,97,116,105,111,110,114,124,0,0,0,114,154,0,0,0, - 218,4,115,112,101,99,218,12,108,111,97,100,101,114,95,99, - 108,97,115,115,218,8,115,117,102,102,105,120,101,115,114,157, - 0,0,0,90,7,100,105,114,110,97,109,101,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,218,23,115,112,101, - 99,95,102,114,111,109,95,102,105,108,101,95,108,111,99,97, - 116,105,111,110,11,2,0,0,115,62,0,0,0,0,12,8, - 4,4,1,10,2,2,1,14,1,14,1,8,2,10,8,16, - 1,6,3,8,1,16,1,14,1,10,1,6,1,6,2,4, - 3,8,2,10,1,2,1,14,1,14,1,6,2,4,1,8, - 2,6,1,12,1,6,1,12,1,12,2,114,165,0,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, - 0,64,0,0,0,115,80,0,0,0,101,0,90,1,100,0, - 90,2,100,1,90,3,100,2,90,4,100,3,90,5,100,4, - 90,6,101,7,100,5,100,6,132,0,131,1,90,8,101,7, - 100,7,100,8,132,0,131,1,90,9,101,7,100,14,100,10, - 100,11,132,1,131,1,90,10,101,7,100,15,100,12,100,13, - 132,1,131,1,90,11,100,9,83,0,41,16,218,21,87,105, + 6,124,8,131,1,130,1,124,1,100,1,107,9,144,1,114, + 124,121,16,116,7,124,1,100,12,25,0,131,1,125,9,87, + 0,110,22,4,0,116,8,107,10,144,1,114,2,1,0,1, + 0,1,0,89,0,110,50,88,0,116,9,124,6,131,1,124, + 9,107,3,144,1,114,52,100,13,106,1,124,2,131,1,125, + 8,116,2,106,3,100,9,124,8,131,2,1,0,116,4,124, + 8,102,1,124,4,142,1,130,1,121,16,124,1,100,14,25, + 0,100,15,64,0,125,10,87,0,110,22,4,0,116,8,107, + 10,144,1,114,90,1,0,1,0,1,0,89,0,110,34,88, + 0,116,9,124,7,131,1,124,10,107,3,144,1,114,124,116, + 4,100,13,106,1,124,2,131,1,102,1,124,4,142,1,130, + 1,124,0,100,7,100,1,133,2,25,0,83,0,41,16,97, + 122,1,0,0,86,97,108,105,100,97,116,101,32,116,104,101, + 32,104,101,97,100,101,114,32,111,102,32,116,104,101,32,112, + 97,115,115,101,100,45,105,110,32,98,121,116,101,99,111,100, + 101,32,97,103,97,105,110,115,116,32,115,111,117,114,99,101, + 95,115,116,97,116,115,32,40,105,102,10,32,32,32,32,103, + 105,118,101,110,41,32,97,110,100,32,114,101,116,117,114,110, + 105,110,103,32,116,104,101,32,98,121,116,101,99,111,100,101, + 32,116,104,97,116,32,99,97,110,32,98,101,32,99,111,109, + 112,105,108,101,100,32,98,121,32,99,111,109,112,105,108,101, + 40,41,46,10,10,32,32,32,32,65,108,108,32,111,116,104, + 101,114,32,97,114,103,117,109,101,110,116,115,32,97,114,101, + 32,117,115,101,100,32,116,111,32,101,110,104,97,110,99,101, + 32,101,114,114,111,114,32,114,101,112,111,114,116,105,110,103, + 46,10,10,32,32,32,32,73,109,112,111,114,116,69,114,114, + 111,114,32,105,115,32,114,97,105,115,101,100,32,119,104,101, + 110,32,116,104,101,32,109,97,103,105,99,32,110,117,109,98, + 101,114,32,105,115,32,105,110,99,111,114,114,101,99,116,32, + 111,114,32,116,104,101,32,98,121,116,101,99,111,100,101,32, + 105,115,10,32,32,32,32,102,111,117,110,100,32,116,111,32, + 98,101,32,115,116,97,108,101,46,32,69,79,70,69,114,114, + 111,114,32,105,115,32,114,97,105,115,101,100,32,119,104,101, + 110,32,116,104,101,32,100,97,116,97,32,105,115,32,102,111, + 117,110,100,32,116,111,32,98,101,10,32,32,32,32,116,114, + 117,110,99,97,116,101,100,46,10,10,32,32,32,32,78,114, + 102,0,0,0,122,10,60,98,121,116,101,99,111,100,101,62, + 114,37,0,0,0,114,14,0,0,0,233,8,0,0,0,233, + 12,0,0,0,122,30,98,97,100,32,109,97,103,105,99,32, + 110,117,109,98,101,114,32,105,110,32,123,33,114,125,58,32, + 123,33,114,125,122,2,123,125,122,43,114,101,97,99,104,101, + 100,32,69,79,70,32,119,104,105,108,101,32,114,101,97,100, + 105,110,103,32,116,105,109,101,115,116,97,109,112,32,105,110, + 32,123,33,114,125,122,48,114,101,97,99,104,101,100,32,69, + 79,70,32,119,104,105,108,101,32,114,101,97,100,105,110,103, + 32,115,105,122,101,32,111,102,32,115,111,117,114,99,101,32, + 105,110,32,123,33,114,125,218,5,109,116,105,109,101,122,26, + 98,121,116,101,99,111,100,101,32,105,115,32,115,116,97,108, + 101,32,102,111,114,32,123,33,114,125,218,4,115,105,122,101, + 108,3,0,0,0,255,127,255,127,3,0,41,10,218,12,77, + 65,71,73,67,95,78,85,77,66,69,82,114,50,0,0,0, + 114,118,0,0,0,218,16,95,118,101,114,98,111,115,101,95, + 109,101,115,115,97,103,101,114,103,0,0,0,114,33,0,0, + 0,218,8,69,79,70,69,114,114,111,114,114,16,0,0,0, + 218,8,75,101,121,69,114,114,111,114,114,21,0,0,0,41, + 11,114,56,0,0,0,218,12,115,111,117,114,99,101,95,115, + 116,97,116,115,114,102,0,0,0,114,37,0,0,0,90,11, + 101,120,99,95,100,101,116,97,105,108,115,90,5,109,97,103, + 105,99,90,13,114,97,119,95,116,105,109,101,115,116,97,109, + 112,90,8,114,97,119,95,115,105,122,101,114,79,0,0,0, + 218,12,115,111,117,114,99,101,95,109,116,105,109,101,218,11, + 115,111,117,114,99,101,95,115,105,122,101,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,25,95,118,97,108, + 105,100,97,116,101,95,98,121,116,101,99,111,100,101,95,104, + 101,97,100,101,114,173,1,0,0,115,76,0,0,0,0,11, + 4,1,8,1,10,3,4,1,8,1,8,1,12,1,12,1, + 12,1,8,1,12,1,12,1,14,1,12,1,10,1,12,1, + 10,1,12,1,10,1,12,1,8,1,10,1,2,1,16,1, + 16,1,6,2,14,1,10,1,12,1,12,1,2,1,16,1, + 16,1,6,2,14,1,12,1,6,1,114,139,0,0,0,99, + 4,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0, + 67,0,0,0,115,80,0,0,0,116,0,106,1,124,0,131, + 1,125,4,116,2,124,4,116,3,131,2,114,56,116,4,106, + 5,100,1,124,2,131,2,1,0,124,3,100,2,107,9,114, + 52,116,6,106,7,124,4,124,3,131,2,1,0,124,4,83, + 0,116,8,100,3,106,9,124,2,131,1,124,1,124,2,100, + 4,141,3,130,1,100,2,83,0,41,5,122,60,67,111,109, + 112,105,108,101,32,98,121,116,101,99,111,100,101,32,97,115, + 32,114,101,116,117,114,110,101,100,32,98,121,32,95,118,97, + 108,105,100,97,116,101,95,98,121,116,101,99,111,100,101,95, + 104,101,97,100,101,114,40,41,46,122,21,99,111,100,101,32, + 111,98,106,101,99,116,32,102,114,111,109,32,123,33,114,125, + 78,122,23,78,111,110,45,99,111,100,101,32,111,98,106,101, + 99,116,32,105,110,32,123,33,114,125,41,2,114,102,0,0, + 0,114,37,0,0,0,41,10,218,7,109,97,114,115,104,97, + 108,90,5,108,111,97,100,115,218,10,105,115,105,110,115,116, + 97,110,99,101,218,10,95,99,111,100,101,95,116,121,112,101, + 114,118,0,0,0,114,133,0,0,0,218,4,95,105,109,112, + 90,16,95,102,105,120,95,99,111,95,102,105,108,101,110,97, + 109,101,114,103,0,0,0,114,50,0,0,0,41,5,114,56, + 0,0,0,114,102,0,0,0,114,93,0,0,0,114,94,0, + 0,0,218,4,99,111,100,101,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,17,95,99,111,109,112,105,108, + 101,95,98,121,116,101,99,111,100,101,228,1,0,0,115,16, + 0,0,0,0,2,10,1,10,1,12,1,8,1,12,1,4, + 2,10,1,114,145,0,0,0,114,62,0,0,0,99,3,0, + 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0, + 0,0,115,56,0,0,0,116,0,116,1,131,1,125,3,124, + 3,106,2,116,3,124,1,131,1,131,1,1,0,124,3,106, + 2,116,3,124,2,131,1,131,1,1,0,124,3,106,2,116, + 4,106,5,124,0,131,1,131,1,1,0,124,3,83,0,41, + 1,122,80,67,111,109,112,105,108,101,32,97,32,99,111,100, + 101,32,111,98,106,101,99,116,32,105,110,116,111,32,98,121, + 116,101,99,111,100,101,32,102,111,114,32,119,114,105,116,105, + 110,103,32,111,117,116,32,116,111,32,97,32,98,121,116,101, + 45,99,111,109,112,105,108,101,100,10,32,32,32,32,102,105, + 108,101,46,41,6,218,9,98,121,116,101,97,114,114,97,121, + 114,132,0,0,0,218,6,101,120,116,101,110,100,114,19,0, + 0,0,114,140,0,0,0,90,5,100,117,109,112,115,41,4, + 114,144,0,0,0,114,130,0,0,0,114,138,0,0,0,114, + 56,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,218,17,95,99,111,100,101,95,116,111,95,98,121, + 116,101,99,111,100,101,240,1,0,0,115,10,0,0,0,0, + 3,8,1,14,1,14,1,16,1,114,148,0,0,0,99,1, + 0,0,0,0,0,0,0,5,0,0,0,4,0,0,0,67, + 0,0,0,115,62,0,0,0,100,1,100,2,108,0,125,1, + 116,1,106,2,124,0,131,1,106,3,125,2,124,1,106,4, + 124,2,131,1,125,3,116,1,106,5,100,2,100,3,131,2, + 125,4,124,4,106,6,124,0,106,6,124,3,100,1,25,0, + 131,1,131,1,83,0,41,4,122,121,68,101,99,111,100,101, + 32,98,121,116,101,115,32,114,101,112,114,101,115,101,110,116, + 105,110,103,32,115,111,117,114,99,101,32,99,111,100,101,32, + 97,110,100,32,114,101,116,117,114,110,32,116,104,101,32,115, + 116,114,105,110,103,46,10,10,32,32,32,32,85,110,105,118, + 101,114,115,97,108,32,110,101,119,108,105,110,101,32,115,117, + 112,112,111,114,116,32,105,115,32,117,115,101,100,32,105,110, + 32,116,104,101,32,100,101,99,111,100,105,110,103,46,10,32, + 32,32,32,114,62,0,0,0,78,84,41,7,218,8,116,111, + 107,101,110,105,122,101,114,52,0,0,0,90,7,66,121,116, + 101,115,73,79,90,8,114,101,97,100,108,105,110,101,90,15, + 100,101,116,101,99,116,95,101,110,99,111,100,105,110,103,90, + 25,73,110,99,114,101,109,101,110,116,97,108,78,101,119,108, + 105,110,101,68,101,99,111,100,101,114,218,6,100,101,99,111, + 100,101,41,5,218,12,115,111,117,114,99,101,95,98,121,116, + 101,115,114,149,0,0,0,90,21,115,111,117,114,99,101,95, + 98,121,116,101,115,95,114,101,97,100,108,105,110,101,218,8, + 101,110,99,111,100,105,110,103,90,15,110,101,119,108,105,110, + 101,95,100,101,99,111,100,101,114,114,4,0,0,0,114,4, + 0,0,0,114,6,0,0,0,218,13,100,101,99,111,100,101, + 95,115,111,117,114,99,101,250,1,0,0,115,10,0,0,0, + 0,5,8,1,12,1,10,1,12,1,114,153,0,0,0,41, + 2,114,124,0,0,0,218,26,115,117,98,109,111,100,117,108, + 101,95,115,101,97,114,99,104,95,108,111,99,97,116,105,111, + 110,115,99,2,0,0,0,2,0,0,0,9,0,0,0,19, + 0,0,0,67,0,0,0,115,18,1,0,0,124,1,100,1, + 107,8,114,60,100,2,125,1,116,0,124,2,100,3,131,2, + 114,70,121,14,124,2,106,1,124,0,131,1,125,1,87,0, + 113,70,4,0,116,2,107,10,114,56,1,0,1,0,1,0, + 89,0,113,70,88,0,110,10,116,3,106,4,124,1,131,1, + 125,1,116,5,106,6,124,0,124,2,124,1,100,4,141,3, + 125,4,100,5,124,4,95,7,124,2,100,1,107,8,114,156, + 120,54,116,8,131,0,68,0,93,40,92,2,125,5,125,6, + 124,1,106,9,116,10,124,6,131,1,131,1,114,108,124,5, + 124,0,124,1,131,2,125,2,124,2,124,4,95,11,80,0, + 113,108,87,0,100,1,83,0,124,3,116,12,107,8,114,222, + 116,0,124,2,100,6,131,2,114,228,121,14,124,2,106,13, + 124,0,131,1,125,7,87,0,110,20,4,0,116,2,107,10, + 114,208,1,0,1,0,1,0,89,0,113,228,88,0,124,7, + 114,228,103,0,124,4,95,14,110,6,124,3,124,4,95,14, + 124,4,106,14,103,0,107,2,144,1,114,14,124,1,144,1, + 114,14,116,15,124,1,131,1,100,7,25,0,125,8,124,4, + 106,14,106,16,124,8,131,1,1,0,124,4,83,0,41,8, + 97,61,1,0,0,82,101,116,117,114,110,32,97,32,109,111, + 100,117,108,101,32,115,112,101,99,32,98,97,115,101,100,32, + 111,110,32,97,32,102,105,108,101,32,108,111,99,97,116,105, + 111,110,46,10,10,32,32,32,32,84,111,32,105,110,100,105, + 99,97,116,101,32,116,104,97,116,32,116,104,101,32,109,111, + 100,117,108,101,32,105,115,32,97,32,112,97,99,107,97,103, + 101,44,32,115,101,116,10,32,32,32,32,115,117,98,109,111, + 100,117,108,101,95,115,101,97,114,99,104,95,108,111,99,97, + 116,105,111,110,115,32,116,111,32,97,32,108,105,115,116,32, + 111,102,32,100,105,114,101,99,116,111,114,121,32,112,97,116, + 104,115,46,32,32,65,110,10,32,32,32,32,101,109,112,116, + 121,32,108,105,115,116,32,105,115,32,115,117,102,102,105,99, + 105,101,110,116,44,32,116,104,111,117,103,104,32,105,116,115, + 32,110,111,116,32,111,116,104,101,114,119,105,115,101,32,117, + 115,101,102,117,108,32,116,111,32,116,104,101,10,32,32,32, + 32,105,109,112,111,114,116,32,115,121,115,116,101,109,46,10, + 10,32,32,32,32,84,104,101,32,108,111,97,100,101,114,32, + 109,117,115,116,32,116,97,107,101,32,97,32,115,112,101,99, + 32,97,115,32,105,116,115,32,111,110,108,121,32,95,95,105, + 110,105,116,95,95,40,41,32,97,114,103,46,10,10,32,32, + 32,32,78,122,9,60,117,110,107,110,111,119,110,62,218,12, + 103,101,116,95,102,105,108,101,110,97,109,101,41,1,218,6, + 111,114,105,103,105,110,84,218,10,105,115,95,112,97,99,107, + 97,103,101,114,62,0,0,0,41,17,114,112,0,0,0,114, + 155,0,0,0,114,103,0,0,0,114,3,0,0,0,114,67, + 0,0,0,114,118,0,0,0,218,10,77,111,100,117,108,101, + 83,112,101,99,90,13,95,115,101,116,95,102,105,108,101,97, + 116,116,114,218,27,95,103,101,116,95,115,117,112,112,111,114, + 116,101,100,95,102,105,108,101,95,108,111,97,100,101,114,115, + 114,96,0,0,0,114,97,0,0,0,114,124,0,0,0,218, + 9,95,80,79,80,85,76,65,84,69,114,157,0,0,0,114, + 154,0,0,0,114,40,0,0,0,218,6,97,112,112,101,110, + 100,41,9,114,102,0,0,0,90,8,108,111,99,97,116,105, + 111,110,114,124,0,0,0,114,154,0,0,0,218,4,115,112, + 101,99,218,12,108,111,97,100,101,114,95,99,108,97,115,115, + 218,8,115,117,102,102,105,120,101,115,114,157,0,0,0,90, + 7,100,105,114,110,97,109,101,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,23,115,112,101,99,95,102,114, + 111,109,95,102,105,108,101,95,108,111,99,97,116,105,111,110, + 11,2,0,0,115,62,0,0,0,0,12,8,4,4,1,10, + 2,2,1,14,1,14,1,8,2,10,8,16,1,6,3,8, + 1,16,1,14,1,10,1,6,1,6,2,4,3,8,2,10, + 1,2,1,14,1,14,1,6,2,4,1,8,2,6,1,12, + 1,6,1,12,1,12,2,114,165,0,0,0,99,0,0,0, + 0,0,0,0,0,0,0,0,0,4,0,0,0,64,0,0, + 0,115,80,0,0,0,101,0,90,1,100,0,90,2,100,1, + 90,3,100,2,90,4,100,3,90,5,100,4,90,6,101,7, + 100,5,100,6,132,0,131,1,90,8,101,7,100,7,100,8, + 132,0,131,1,90,9,101,7,100,14,100,10,100,11,132,1, + 131,1,90,10,101,7,100,15,100,12,100,13,132,1,131,1, + 90,11,100,9,83,0,41,16,218,21,87,105,110,100,111,119, + 115,82,101,103,105,115,116,114,121,70,105,110,100,101,114,122, + 62,77,101,116,97,32,112,97,116,104,32,102,105,110,100,101, + 114,32,102,111,114,32,109,111,100,117,108,101,115,32,100,101, + 99,108,97,114,101,100,32,105,110,32,116,104,101,32,87,105, + 110,100,111,119,115,32,114,101,103,105,115,116,114,121,46,122, + 59,83,111,102,116,119,97,114,101,92,80,121,116,104,111,110, + 92,80,121,116,104,111,110,67,111,114,101,92,123,115,121,115, + 95,118,101,114,115,105,111,110,125,92,77,111,100,117,108,101, + 115,92,123,102,117,108,108,110,97,109,101,125,122,65,83,111, + 102,116,119,97,114,101,92,80,121,116,104,111,110,92,80,121, + 116,104,111,110,67,111,114,101,92,123,115,121,115,95,118,101, + 114,115,105,111,110,125,92,77,111,100,117,108,101,115,92,123, + 102,117,108,108,110,97,109,101,125,92,68,101,98,117,103,70, + 99,2,0,0,0,0,0,0,0,2,0,0,0,11,0,0, + 0,67,0,0,0,115,50,0,0,0,121,14,116,0,106,1, + 116,0,106,2,124,1,131,2,83,0,4,0,116,3,107,10, + 114,44,1,0,1,0,1,0,116,0,106,1,116,0,106,4, + 124,1,131,2,83,0,88,0,100,0,83,0,41,1,78,41, + 5,218,7,95,119,105,110,114,101,103,90,7,79,112,101,110, + 75,101,121,90,17,72,75,69,89,95,67,85,82,82,69,78, + 84,95,85,83,69,82,114,42,0,0,0,90,18,72,75,69, + 89,95,76,79,67,65,76,95,77,65,67,72,73,78,69,41, + 2,218,3,99,108,115,114,5,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,14,95,111,112,101, + 110,95,114,101,103,105,115,116,114,121,91,2,0,0,115,8, + 0,0,0,0,2,2,1,14,1,14,1,122,36,87,105,110, + 100,111,119,115,82,101,103,105,115,116,114,121,70,105,110,100, + 101,114,46,95,111,112,101,110,95,114,101,103,105,115,116,114, + 121,99,2,0,0,0,0,0,0,0,6,0,0,0,16,0, + 0,0,67,0,0,0,115,112,0,0,0,124,0,106,0,114, + 14,124,0,106,1,125,2,110,6,124,0,106,2,125,2,124, + 2,106,3,124,1,100,1,116,4,106,5,100,0,100,2,133, + 2,25,0,22,0,100,3,141,2,125,3,121,38,124,0,106, + 6,124,3,131,1,143,18,125,4,116,7,106,8,124,4,100, + 4,131,2,125,5,87,0,100,0,81,0,82,0,88,0,87, + 0,110,20,4,0,116,9,107,10,114,106,1,0,1,0,1, + 0,100,0,83,0,88,0,124,5,83,0,41,5,78,122,5, + 37,100,46,37,100,114,59,0,0,0,41,2,114,123,0,0, + 0,90,11,115,121,115,95,118,101,114,115,105,111,110,114,32, + 0,0,0,41,10,218,11,68,69,66,85,71,95,66,85,73, + 76,68,218,18,82,69,71,73,83,84,82,89,95,75,69,89, + 95,68,69,66,85,71,218,12,82,69,71,73,83,84,82,89, + 95,75,69,89,114,50,0,0,0,114,8,0,0,0,218,12, + 118,101,114,115,105,111,110,95,105,110,102,111,114,169,0,0, + 0,114,167,0,0,0,90,10,81,117,101,114,121,86,97,108, + 117,101,114,42,0,0,0,41,6,114,168,0,0,0,114,123, + 0,0,0,90,12,114,101,103,105,115,116,114,121,95,107,101, + 121,114,5,0,0,0,90,4,104,107,101,121,218,8,102,105, + 108,101,112,97,116,104,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,218,16,95,115,101,97,114,99,104,95,114, + 101,103,105,115,116,114,121,98,2,0,0,115,22,0,0,0, + 0,2,6,1,8,2,6,1,6,1,22,1,2,1,12,1, + 26,1,14,1,6,1,122,38,87,105,110,100,111,119,115,82, + 101,103,105,115,116,114,121,70,105,110,100,101,114,46,95,115, + 101,97,114,99,104,95,114,101,103,105,115,116,114,121,78,99, + 4,0,0,0,0,0,0,0,8,0,0,0,14,0,0,0, + 67,0,0,0,115,120,0,0,0,124,0,106,0,124,1,131, + 1,125,4,124,4,100,0,107,8,114,22,100,0,83,0,121, + 12,116,1,124,4,131,1,1,0,87,0,110,20,4,0,116, + 2,107,10,114,54,1,0,1,0,1,0,100,0,83,0,88, + 0,120,58,116,3,131,0,68,0,93,48,92,2,125,5,125, + 6,124,4,106,4,116,5,124,6,131,1,131,1,114,64,116, + 6,106,7,124,1,124,5,124,1,124,4,131,2,124,4,100, + 1,141,3,125,7,124,7,83,0,113,64,87,0,100,0,83, + 0,41,2,78,41,1,114,156,0,0,0,41,8,114,175,0, + 0,0,114,41,0,0,0,114,42,0,0,0,114,159,0,0, + 0,114,96,0,0,0,114,97,0,0,0,114,118,0,0,0, + 218,16,115,112,101,99,95,102,114,111,109,95,108,111,97,100, + 101,114,41,8,114,168,0,0,0,114,123,0,0,0,114,37, + 0,0,0,218,6,116,97,114,103,101,116,114,174,0,0,0, + 114,124,0,0,0,114,164,0,0,0,114,162,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,9, + 102,105,110,100,95,115,112,101,99,113,2,0,0,115,26,0, + 0,0,0,2,10,1,8,1,4,1,2,1,12,1,14,1, + 6,1,16,1,14,1,6,1,8,1,8,1,122,31,87,105, 110,100,111,119,115,82,101,103,105,115,116,114,121,70,105,110, - 100,101,114,122,62,77,101,116,97,32,112,97,116,104,32,102, - 105,110,100,101,114,32,102,111,114,32,109,111,100,117,108,101, - 115,32,100,101,99,108,97,114,101,100,32,105,110,32,116,104, - 101,32,87,105,110,100,111,119,115,32,114,101,103,105,115,116, - 114,121,46,122,59,83,111,102,116,119,97,114,101,92,80,121, - 116,104,111,110,92,80,121,116,104,111,110,67,111,114,101,92, - 123,115,121,115,95,118,101,114,115,105,111,110,125,92,77,111, - 100,117,108,101,115,92,123,102,117,108,108,110,97,109,101,125, - 122,65,83,111,102,116,119,97,114,101,92,80,121,116,104,111, - 110,92,80,121,116,104,111,110,67,111,114,101,92,123,115,121, - 115,95,118,101,114,115,105,111,110,125,92,77,111,100,117,108, - 101,115,92,123,102,117,108,108,110,97,109,101,125,92,68,101, - 98,117,103,70,99,2,0,0,0,0,0,0,0,2,0,0, - 0,11,0,0,0,67,0,0,0,115,50,0,0,0,121,14, - 116,0,106,1,116,0,106,2,124,1,131,2,83,0,4,0, - 116,3,107,10,114,44,1,0,1,0,1,0,116,0,106,1, - 116,0,106,4,124,1,131,2,83,0,88,0,100,0,83,0, - 41,1,78,41,5,218,7,95,119,105,110,114,101,103,90,7, - 79,112,101,110,75,101,121,90,17,72,75,69,89,95,67,85, - 82,82,69,78,84,95,85,83,69,82,114,42,0,0,0,90, - 18,72,75,69,89,95,76,79,67,65,76,95,77,65,67,72, - 73,78,69,41,2,218,3,99,108,115,114,5,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,14, - 95,111,112,101,110,95,114,101,103,105,115,116,114,121,91,2, - 0,0,115,8,0,0,0,0,2,2,1,14,1,14,1,122, - 36,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, - 70,105,110,100,101,114,46,95,111,112,101,110,95,114,101,103, - 105,115,116,114,121,99,2,0,0,0,0,0,0,0,6,0, - 0,0,16,0,0,0,67,0,0,0,115,112,0,0,0,124, - 0,106,0,114,14,124,0,106,1,125,2,110,6,124,0,106, - 2,125,2,124,2,106,3,124,1,100,1,116,4,106,5,100, - 0,100,2,133,2,25,0,22,0,100,3,141,2,125,3,121, - 38,124,0,106,6,124,3,131,1,143,18,125,4,116,7,106, - 8,124,4,100,4,131,2,125,5,87,0,100,0,81,0,82, - 0,88,0,87,0,110,20,4,0,116,9,107,10,114,106,1, - 0,1,0,1,0,100,0,83,0,88,0,124,5,83,0,41, - 5,78,122,5,37,100,46,37,100,114,59,0,0,0,41,2, - 114,123,0,0,0,90,11,115,121,115,95,118,101,114,115,105, - 111,110,114,32,0,0,0,41,10,218,11,68,69,66,85,71, - 95,66,85,73,76,68,218,18,82,69,71,73,83,84,82,89, - 95,75,69,89,95,68,69,66,85,71,218,12,82,69,71,73, - 83,84,82,89,95,75,69,89,114,50,0,0,0,114,8,0, - 0,0,218,12,118,101,114,115,105,111,110,95,105,110,102,111, - 114,169,0,0,0,114,167,0,0,0,90,10,81,117,101,114, - 121,86,97,108,117,101,114,42,0,0,0,41,6,114,168,0, - 0,0,114,123,0,0,0,90,12,114,101,103,105,115,116,114, - 121,95,107,101,121,114,5,0,0,0,90,4,104,107,101,121, - 218,8,102,105,108,101,112,97,116,104,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,218,16,95,115,101,97,114, - 99,104,95,114,101,103,105,115,116,114,121,98,2,0,0,115, - 22,0,0,0,0,2,6,1,8,2,6,1,6,1,22,1, - 2,1,12,1,26,1,14,1,6,1,122,38,87,105,110,100, - 111,119,115,82,101,103,105,115,116,114,121,70,105,110,100,101, - 114,46,95,115,101,97,114,99,104,95,114,101,103,105,115,116, - 114,121,78,99,4,0,0,0,0,0,0,0,8,0,0,0, - 14,0,0,0,67,0,0,0,115,120,0,0,0,124,0,106, - 0,124,1,131,1,125,4,124,4,100,0,107,8,114,22,100, - 0,83,0,121,12,116,1,124,4,131,1,1,0,87,0,110, - 20,4,0,116,2,107,10,114,54,1,0,1,0,1,0,100, - 0,83,0,88,0,120,58,116,3,131,0,68,0,93,48,92, - 2,125,5,125,6,124,4,106,4,116,5,124,6,131,1,131, - 1,114,64,116,6,106,7,124,1,124,5,124,1,124,4,131, - 2,124,4,100,1,141,3,125,7,124,7,83,0,113,64,87, - 0,100,0,83,0,41,2,78,41,1,114,156,0,0,0,41, - 8,114,175,0,0,0,114,41,0,0,0,114,42,0,0,0, - 114,159,0,0,0,114,96,0,0,0,114,97,0,0,0,114, - 118,0,0,0,218,16,115,112,101,99,95,102,114,111,109,95, - 108,111,97,100,101,114,41,8,114,168,0,0,0,114,123,0, - 0,0,114,37,0,0,0,218,6,116,97,114,103,101,116,114, - 174,0,0,0,114,124,0,0,0,114,164,0,0,0,114,162, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,9,102,105,110,100,95,115,112,101,99,113,2,0, - 0,115,26,0,0,0,0,2,10,1,8,1,4,1,2,1, - 12,1,14,1,6,1,16,1,14,1,6,1,8,1,8,1, - 122,31,87,105,110,100,111,119,115,82,101,103,105,115,116,114, - 121,70,105,110,100,101,114,46,102,105,110,100,95,115,112,101, - 99,99,3,0,0,0,0,0,0,0,4,0,0,0,3,0, - 0,0,67,0,0,0,115,36,0,0,0,124,0,106,0,124, - 1,124,2,131,2,125,3,124,3,100,1,107,9,114,28,124, - 3,106,1,83,0,110,4,100,1,83,0,100,1,83,0,41, - 2,122,108,70,105,110,100,32,109,111,100,117,108,101,32,110, - 97,109,101,100,32,105,110,32,116,104,101,32,114,101,103,105, - 115,116,114,121,46,10,10,32,32,32,32,32,32,32,32,84, - 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, - 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,101, - 120,101,99,95,109,111,100,117,108,101,40,41,32,105,110,115, - 116,101,97,100,46,10,10,32,32,32,32,32,32,32,32,78, - 41,2,114,178,0,0,0,114,124,0,0,0,41,4,114,168, - 0,0,0,114,123,0,0,0,114,37,0,0,0,114,162,0, - 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,218,11,102,105,110,100,95,109,111,100,117,108,101,129,2, - 0,0,115,8,0,0,0,0,7,12,1,8,1,8,2,122, - 33,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, - 70,105,110,100,101,114,46,102,105,110,100,95,109,111,100,117, - 108,101,41,2,78,78,41,1,78,41,12,114,109,0,0,0, - 114,108,0,0,0,114,110,0,0,0,114,111,0,0,0,114, - 172,0,0,0,114,171,0,0,0,114,170,0,0,0,218,11, - 99,108,97,115,115,109,101,116,104,111,100,114,169,0,0,0, - 114,175,0,0,0,114,178,0,0,0,114,179,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,166,0,0,0,79,2,0,0,115,20,0,0, - 0,8,2,4,3,4,3,4,2,4,2,12,7,12,15,2, - 1,12,15,2,1,114,166,0,0,0,99,0,0,0,0,0, - 0,0,0,0,0,0,0,2,0,0,0,64,0,0,0,115, - 48,0,0,0,101,0,90,1,100,0,90,2,100,1,90,3, - 100,2,100,3,132,0,90,4,100,4,100,5,132,0,90,5, - 100,6,100,7,132,0,90,6,100,8,100,9,132,0,90,7, - 100,10,83,0,41,11,218,13,95,76,111,97,100,101,114,66, - 97,115,105,99,115,122,83,66,97,115,101,32,99,108,97,115, - 115,32,111,102,32,99,111,109,109,111,110,32,99,111,100,101, - 32,110,101,101,100,101,100,32,98,121,32,98,111,116,104,32, - 83,111,117,114,99,101,76,111,97,100,101,114,32,97,110,100, - 10,32,32,32,32,83,111,117,114,99,101,108,101,115,115,70, - 105,108,101,76,111,97,100,101,114,46,99,2,0,0,0,0, - 0,0,0,5,0,0,0,3,0,0,0,67,0,0,0,115, - 64,0,0,0,116,0,124,0,106,1,124,1,131,1,131,1, - 100,1,25,0,125,2,124,2,106,2,100,2,100,1,131,2, - 100,3,25,0,125,3,124,1,106,3,100,2,131,1,100,4, - 25,0,125,4,124,3,100,5,107,2,111,62,124,4,100,5, - 107,3,83,0,41,6,122,141,67,111,110,99,114,101,116,101, - 32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32, - 111,102,32,73,110,115,112,101,99,116,76,111,97,100,101,114, - 46,105,115,95,112,97,99,107,97,103,101,32,98,121,32,99, - 104,101,99,107,105,110,103,32,105,102,10,32,32,32,32,32, - 32,32,32,116,104,101,32,112,97,116,104,32,114,101,116,117, - 114,110,101,100,32,98,121,32,103,101,116,95,102,105,108,101, - 110,97,109,101,32,104,97,115,32,97,32,102,105,108,101,110, - 97,109,101,32,111,102,32,39,95,95,105,110,105,116,95,95, - 46,112,121,39,46,114,31,0,0,0,114,61,0,0,0,114, - 62,0,0,0,114,59,0,0,0,218,8,95,95,105,110,105, - 116,95,95,41,4,114,40,0,0,0,114,155,0,0,0,114, - 36,0,0,0,114,34,0,0,0,41,5,114,104,0,0,0, - 114,123,0,0,0,114,98,0,0,0,90,13,102,105,108,101, - 110,97,109,101,95,98,97,115,101,90,9,116,97,105,108,95, - 110,97,109,101,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,157,0,0,0,148,2,0,0,115,8,0,0, - 0,0,3,18,1,16,1,14,1,122,24,95,76,111,97,100, - 101,114,66,97,115,105,99,115,46,105,115,95,112,97,99,107, - 97,103,101,99,2,0,0,0,0,0,0,0,2,0,0,0, - 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, - 0,41,2,122,42,85,115,101,32,100,101,102,97,117,108,116, - 32,115,101,109,97,110,116,105,99,115,32,102,111,114,32,109, - 111,100,117,108,101,32,99,114,101,97,116,105,111,110,46,78, - 114,4,0,0,0,41,2,114,104,0,0,0,114,162,0,0, - 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,13,99,114,101,97,116,101,95,109,111,100,117,108,101,156, - 2,0,0,115,0,0,0,0,122,27,95,76,111,97,100,101, - 114,66,97,115,105,99,115,46,99,114,101,97,116,101,95,109, - 111,100,117,108,101,99,2,0,0,0,0,0,0,0,3,0, - 0,0,4,0,0,0,67,0,0,0,115,56,0,0,0,124, - 0,106,0,124,1,106,1,131,1,125,2,124,2,100,1,107, - 8,114,36,116,2,100,2,106,3,124,1,106,1,131,1,131, - 1,130,1,116,4,106,5,116,6,124,2,124,1,106,7,131, - 3,1,0,100,1,83,0,41,3,122,19,69,120,101,99,117, - 116,101,32,116,104,101,32,109,111,100,117,108,101,46,78,122, - 52,99,97,110,110,111,116,32,108,111,97,100,32,109,111,100, - 117,108,101,32,123,33,114,125,32,119,104,101,110,32,103,101, - 116,95,99,111,100,101,40,41,32,114,101,116,117,114,110,115, - 32,78,111,110,101,41,8,218,8,103,101,116,95,99,111,100, - 101,114,109,0,0,0,114,103,0,0,0,114,50,0,0,0, - 114,118,0,0,0,218,25,95,99,97,108,108,95,119,105,116, - 104,95,102,114,97,109,101,115,95,114,101,109,111,118,101,100, - 218,4,101,120,101,99,114,115,0,0,0,41,3,114,104,0, - 0,0,218,6,109,111,100,117,108,101,114,144,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,11, - 101,120,101,99,95,109,111,100,117,108,101,159,2,0,0,115, - 10,0,0,0,0,2,12,1,8,1,6,1,10,1,122,25, - 95,76,111,97,100,101,114,66,97,115,105,99,115,46,101,120, - 101,99,95,109,111,100,117,108,101,99,2,0,0,0,0,0, - 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,12, - 0,0,0,116,0,106,1,124,0,124,1,131,2,83,0,41, - 1,122,26,84,104,105,115,32,109,111,100,117,108,101,32,105, - 115,32,100,101,112,114,101,99,97,116,101,100,46,41,2,114, - 118,0,0,0,218,17,95,108,111,97,100,95,109,111,100,117, - 108,101,95,115,104,105,109,41,2,114,104,0,0,0,114,123, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,11,108,111,97,100,95,109,111,100,117,108,101,167, - 2,0,0,115,2,0,0,0,0,2,122,25,95,76,111,97, - 100,101,114,66,97,115,105,99,115,46,108,111,97,100,95,109, - 111,100,117,108,101,78,41,8,114,109,0,0,0,114,108,0, - 0,0,114,110,0,0,0,114,111,0,0,0,114,157,0,0, - 0,114,183,0,0,0,114,188,0,0,0,114,190,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,181,0,0,0,143,2,0,0,115,10,0, - 0,0,8,3,4,2,8,8,8,3,8,8,114,181,0,0, - 0,99,0,0,0,0,0,0,0,0,0,0,0,0,3,0, - 0,0,64,0,0,0,115,74,0,0,0,101,0,90,1,100, - 0,90,2,100,1,100,2,132,0,90,3,100,3,100,4,132, - 0,90,4,100,5,100,6,132,0,90,5,100,7,100,8,132, - 0,90,6,100,9,100,10,132,0,90,7,100,18,100,12,156, - 1,100,13,100,14,132,2,90,8,100,15,100,16,132,0,90, - 9,100,17,83,0,41,19,218,12,83,111,117,114,99,101,76, - 111,97,100,101,114,99,2,0,0,0,0,0,0,0,2,0, - 0,0,1,0,0,0,67,0,0,0,115,8,0,0,0,116, - 0,130,1,100,1,83,0,41,2,122,178,79,112,116,105,111, - 110,97,108,32,109,101,116,104,111,100,32,116,104,97,116,32, - 114,101,116,117,114,110,115,32,116,104,101,32,109,111,100,105, - 102,105,99,97,116,105,111,110,32,116,105,109,101,32,40,97, - 110,32,105,110,116,41,32,102,111,114,32,116,104,101,10,32, - 32,32,32,32,32,32,32,115,112,101,99,105,102,105,101,100, - 32,112,97,116,104,44,32,119,104,101,114,101,32,112,97,116, - 104,32,105,115,32,97,32,115,116,114,46,10,10,32,32,32, - 32,32,32,32,32,82,97,105,115,101,115,32,73,79,69,114, - 114,111,114,32,119,104,101,110,32,116,104,101,32,112,97,116, - 104,32,99,97,110,110,111,116,32,98,101,32,104,97,110,100, - 108,101,100,46,10,32,32,32,32,32,32,32,32,78,41,1, - 218,7,73,79,69,114,114,111,114,41,2,114,104,0,0,0, - 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,10,112,97,116,104,95,109,116,105,109,101, - 174,2,0,0,115,2,0,0,0,0,6,122,23,83,111,117, - 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,109, - 116,105,109,101,99,2,0,0,0,0,0,0,0,2,0,0, - 0,3,0,0,0,67,0,0,0,115,14,0,0,0,100,1, - 124,0,106,0,124,1,131,1,105,1,83,0,41,2,97,170, - 1,0,0,79,112,116,105,111,110,97,108,32,109,101,116,104, - 111,100,32,114,101,116,117,114,110,105,110,103,32,97,32,109, - 101,116,97,100,97,116,97,32,100,105,99,116,32,102,111,114, - 32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,112, - 97,116,104,10,32,32,32,32,32,32,32,32,116,111,32,98, - 121,32,116,104,101,32,112,97,116,104,32,40,115,116,114,41, - 46,10,32,32,32,32,32,32,32,32,80,111,115,115,105,98, - 108,101,32,107,101,121,115,58,10,32,32,32,32,32,32,32, - 32,45,32,39,109,116,105,109,101,39,32,40,109,97,110,100, - 97,116,111,114,121,41,32,105,115,32,116,104,101,32,110,117, - 109,101,114,105,99,32,116,105,109,101,115,116,97,109,112,32, - 111,102,32,108,97,115,116,32,115,111,117,114,99,101,10,32, - 32,32,32,32,32,32,32,32,32,99,111,100,101,32,109,111, - 100,105,102,105,99,97,116,105,111,110,59,10,32,32,32,32, - 32,32,32,32,45,32,39,115,105,122,101,39,32,40,111,112, - 116,105,111,110,97,108,41,32,105,115,32,116,104,101,32,115, - 105,122,101,32,105,110,32,98,121,116,101,115,32,111,102,32, - 116,104,101,32,115,111,117,114,99,101,32,99,111,100,101,46, - 10,10,32,32,32,32,32,32,32,32,73,109,112,108,101,109, - 101,110,116,105,110,103,32,116,104,105,115,32,109,101,116,104, - 111,100,32,97,108,108,111,119,115,32,116,104,101,32,108,111, - 97,100,101,114,32,116,111,32,114,101,97,100,32,98,121,116, - 101,99,111,100,101,32,102,105,108,101,115,46,10,32,32,32, - 32,32,32,32,32,82,97,105,115,101,115,32,73,79,69,114, - 114,111,114,32,119,104,101,110,32,116,104,101,32,112,97,116, - 104,32,99,97,110,110,111,116,32,98,101,32,104,97,110,100, - 108,101,100,46,10,32,32,32,32,32,32,32,32,114,130,0, - 0,0,41,1,114,193,0,0,0,41,2,114,104,0,0,0, - 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,10,112,97,116,104,95,115,116,97,116,115, - 182,2,0,0,115,2,0,0,0,0,11,122,23,83,111,117, - 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,115, - 116,97,116,115,99,4,0,0,0,0,0,0,0,4,0,0, - 0,3,0,0,0,67,0,0,0,115,12,0,0,0,124,0, - 106,0,124,2,124,3,131,2,83,0,41,1,122,228,79,112, - 116,105,111,110,97,108,32,109,101,116,104,111,100,32,119,104, - 105,99,104,32,119,114,105,116,101,115,32,100,97,116,97,32, - 40,98,121,116,101,115,41,32,116,111,32,97,32,102,105,108, - 101,32,112,97,116,104,32,40,97,32,115,116,114,41,46,10, - 10,32,32,32,32,32,32,32,32,73,109,112,108,101,109,101, - 110,116,105,110,103,32,116,104,105,115,32,109,101,116,104,111, - 100,32,97,108,108,111,119,115,32,102,111,114,32,116,104,101, - 32,119,114,105,116,105,110,103,32,111,102,32,98,121,116,101, - 99,111,100,101,32,102,105,108,101,115,46,10,10,32,32,32, - 32,32,32,32,32,84,104,101,32,115,111,117,114,99,101,32, - 112,97,116,104,32,105,115,32,110,101,101,100,101,100,32,105, - 110,32,111,114,100,101,114,32,116,111,32,99,111,114,114,101, - 99,116,108,121,32,116,114,97,110,115,102,101,114,32,112,101, - 114,109,105,115,115,105,111,110,115,10,32,32,32,32,32,32, - 32,32,41,1,218,8,115,101,116,95,100,97,116,97,41,4, - 114,104,0,0,0,114,94,0,0,0,90,10,99,97,99,104, - 101,95,112,97,116,104,114,56,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,218,15,95,99,97,99, - 104,101,95,98,121,116,101,99,111,100,101,195,2,0,0,115, - 2,0,0,0,0,8,122,28,83,111,117,114,99,101,76,111, - 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, - 99,111,100,101,99,3,0,0,0,0,0,0,0,3,0,0, - 0,1,0,0,0,67,0,0,0,115,4,0,0,0,100,1, - 83,0,41,2,122,150,79,112,116,105,111,110,97,108,32,109, - 101,116,104,111,100,32,119,104,105,99,104,32,119,114,105,116, - 101,115,32,100,97,116,97,32,40,98,121,116,101,115,41,32, - 116,111,32,97,32,102,105,108,101,32,112,97,116,104,32,40, - 97,32,115,116,114,41,46,10,10,32,32,32,32,32,32,32, - 32,73,109,112,108,101,109,101,110,116,105,110,103,32,116,104, - 105,115,32,109,101,116,104,111,100,32,97,108,108,111,119,115, - 32,102,111,114,32,116,104,101,32,119,114,105,116,105,110,103, - 32,111,102,32,98,121,116,101,99,111,100,101,32,102,105,108, - 101,115,46,10,32,32,32,32,32,32,32,32,78,114,4,0, - 0,0,41,3,114,104,0,0,0,114,37,0,0,0,114,56, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,195,0,0,0,205,2,0,0,115,0,0,0,0, - 122,21,83,111,117,114,99,101,76,111,97,100,101,114,46,115, - 101,116,95,100,97,116,97,99,2,0,0,0,0,0,0,0, - 5,0,0,0,16,0,0,0,67,0,0,0,115,82,0,0, - 0,124,0,106,0,124,1,131,1,125,2,121,14,124,0,106, - 1,124,2,131,1,125,3,87,0,110,48,4,0,116,2,107, - 10,114,72,1,0,125,4,1,0,122,20,116,3,100,1,124, - 1,100,2,141,2,124,4,130,2,87,0,89,0,100,3,100, - 3,125,4,126,4,88,0,110,2,88,0,116,4,124,3,131, - 1,83,0,41,4,122,52,67,111,110,99,114,101,116,101,32, - 105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111, - 102,32,73,110,115,112,101,99,116,76,111,97,100,101,114,46, - 103,101,116,95,115,111,117,114,99,101,46,122,39,115,111,117, - 114,99,101,32,110,111,116,32,97,118,97,105,108,97,98,108, - 101,32,116,104,114,111,117,103,104,32,103,101,116,95,100,97, - 116,97,40,41,41,1,114,102,0,0,0,78,41,5,114,155, - 0,0,0,218,8,103,101,116,95,100,97,116,97,114,42,0, - 0,0,114,103,0,0,0,114,153,0,0,0,41,5,114,104, - 0,0,0,114,123,0,0,0,114,37,0,0,0,114,151,0, - 0,0,218,3,101,120,99,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,10,103,101,116,95,115,111,117,114, - 99,101,212,2,0,0,115,14,0,0,0,0,2,10,1,2, - 1,14,1,16,1,4,1,28,1,122,23,83,111,117,114,99, - 101,76,111,97,100,101,114,46,103,101,116,95,115,111,117,114, - 99,101,114,31,0,0,0,41,1,218,9,95,111,112,116,105, - 109,105,122,101,99,3,0,0,0,1,0,0,0,4,0,0, - 0,8,0,0,0,67,0,0,0,115,22,0,0,0,116,0, - 106,1,116,2,124,1,124,2,100,1,100,2,124,3,100,3, - 141,6,83,0,41,4,122,130,82,101,116,117,114,110,32,116, - 104,101,32,99,111,100,101,32,111,98,106,101,99,116,32,99, - 111,109,112,105,108,101,100,32,102,114,111,109,32,115,111,117, - 114,99,101,46,10,10,32,32,32,32,32,32,32,32,84,104, - 101,32,39,100,97,116,97,39,32,97,114,103,117,109,101,110, - 116,32,99,97,110,32,98,101,32,97,110,121,32,111,98,106, - 101,99,116,32,116,121,112,101,32,116,104,97,116,32,99,111, - 109,112,105,108,101,40,41,32,115,117,112,112,111,114,116,115, - 46,10,32,32,32,32,32,32,32,32,114,186,0,0,0,84, - 41,2,218,12,100,111,110,116,95,105,110,104,101,114,105,116, - 114,72,0,0,0,41,3,114,118,0,0,0,114,185,0,0, - 0,218,7,99,111,109,112,105,108,101,41,4,114,104,0,0, - 0,114,56,0,0,0,114,37,0,0,0,114,200,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, - 14,115,111,117,114,99,101,95,116,111,95,99,111,100,101,222, - 2,0,0,115,4,0,0,0,0,5,12,1,122,27,83,111, - 117,114,99,101,76,111,97,100,101,114,46,115,111,117,114,99, - 101,95,116,111,95,99,111,100,101,99,2,0,0,0,0,0, - 0,0,10,0,0,0,43,0,0,0,67,0,0,0,115,94, - 1,0,0,124,0,106,0,124,1,131,1,125,2,100,1,125, - 3,121,12,116,1,124,2,131,1,125,4,87,0,110,24,4, - 0,116,2,107,10,114,50,1,0,1,0,1,0,100,1,125, - 4,89,0,110,162,88,0,121,14,124,0,106,3,124,2,131, - 1,125,5,87,0,110,20,4,0,116,4,107,10,114,86,1, - 0,1,0,1,0,89,0,110,126,88,0,116,5,124,5,100, - 2,25,0,131,1,125,3,121,14,124,0,106,6,124,4,131, - 1,125,6,87,0,110,20,4,0,116,7,107,10,114,134,1, - 0,1,0,1,0,89,0,110,78,88,0,121,20,116,8,124, - 6,124,5,124,1,124,4,100,3,141,4,125,7,87,0,110, - 24,4,0,116,9,116,10,102,2,107,10,114,180,1,0,1, - 0,1,0,89,0,110,32,88,0,116,11,106,12,100,4,124, - 4,124,2,131,3,1,0,116,13,124,7,124,1,124,4,124, - 2,100,5,141,4,83,0,124,0,106,6,124,2,131,1,125, - 8,124,0,106,14,124,8,124,2,131,2,125,9,116,11,106, - 12,100,6,124,2,131,2,1,0,116,15,106,16,12,0,144, - 1,114,90,124,4,100,1,107,9,144,1,114,90,124,3,100, - 1,107,9,144,1,114,90,116,17,124,9,124,3,116,18,124, - 8,131,1,131,3,125,6,121,30,124,0,106,19,124,2,124, - 4,124,6,131,3,1,0,116,11,106,12,100,7,124,4,131, - 2,1,0,87,0,110,22,4,0,116,2,107,10,144,1,114, - 88,1,0,1,0,1,0,89,0,110,2,88,0,124,9,83, - 0,41,8,122,190,67,111,110,99,114,101,116,101,32,105,109, - 112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32, - 73,110,115,112,101,99,116,76,111,97,100,101,114,46,103,101, - 116,95,99,111,100,101,46,10,10,32,32,32,32,32,32,32, - 32,82,101,97,100,105,110,103,32,111,102,32,98,121,116,101, - 99,111,100,101,32,114,101,113,117,105,114,101,115,32,112,97, - 116,104,95,115,116,97,116,115,32,116,111,32,98,101,32,105, - 109,112,108,101,109,101,110,116,101,100,46,32,84,111,32,119, - 114,105,116,101,10,32,32,32,32,32,32,32,32,98,121,116, - 101,99,111,100,101,44,32,115,101,116,95,100,97,116,97,32, - 109,117,115,116,32,97,108,115,111,32,98,101,32,105,109,112, - 108,101,109,101,110,116,101,100,46,10,10,32,32,32,32,32, - 32,32,32,78,114,130,0,0,0,41,3,114,136,0,0,0, - 114,102,0,0,0,114,37,0,0,0,122,13,123,125,32,109, - 97,116,99,104,101,115,32,123,125,41,3,114,102,0,0,0, - 114,93,0,0,0,114,94,0,0,0,122,19,99,111,100,101, - 32,111,98,106,101,99,116,32,102,114,111,109,32,123,125,122, - 10,119,114,111,116,101,32,123,33,114,125,41,20,114,155,0, - 0,0,114,83,0,0,0,114,70,0,0,0,114,194,0,0, - 0,114,192,0,0,0,114,16,0,0,0,114,197,0,0,0, - 114,42,0,0,0,114,139,0,0,0,114,103,0,0,0,114, - 134,0,0,0,114,118,0,0,0,114,133,0,0,0,114,145, - 0,0,0,114,203,0,0,0,114,8,0,0,0,218,19,100, - 111,110,116,95,119,114,105,116,101,95,98,121,116,101,99,111, - 100,101,114,148,0,0,0,114,33,0,0,0,114,196,0,0, - 0,41,10,114,104,0,0,0,114,123,0,0,0,114,94,0, - 0,0,114,137,0,0,0,114,93,0,0,0,218,2,115,116, - 114,56,0,0,0,218,10,98,121,116,101,115,95,100,97,116, - 97,114,151,0,0,0,90,11,99,111,100,101,95,111,98,106, - 101,99,116,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,184,0,0,0,230,2,0,0,115,78,0,0,0, - 0,7,10,1,4,1,2,1,12,1,14,1,10,2,2,1, - 14,1,14,1,6,2,12,1,2,1,14,1,14,1,6,2, - 2,1,4,1,4,1,12,1,18,1,6,2,8,1,6,1, - 6,1,2,1,8,1,10,1,12,1,12,1,20,1,10,1, - 6,1,10,1,2,1,14,1,16,1,16,1,6,1,122,21, - 83,111,117,114,99,101,76,111,97,100,101,114,46,103,101,116, - 95,99,111,100,101,78,114,91,0,0,0,41,10,114,109,0, - 0,0,114,108,0,0,0,114,110,0,0,0,114,193,0,0, - 0,114,194,0,0,0,114,196,0,0,0,114,195,0,0,0, - 114,199,0,0,0,114,203,0,0,0,114,184,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,191,0,0,0,172,2,0,0,115,14,0,0, - 0,8,2,8,8,8,13,8,10,8,7,8,10,14,8,114, - 191,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, - 0,4,0,0,0,0,0,0,0,115,80,0,0,0,101,0, + 100,101,114,46,102,105,110,100,95,115,112,101,99,99,3,0, + 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0, + 0,0,115,34,0,0,0,124,0,106,0,124,1,124,2,131, + 2,125,3,124,3,100,1,107,9,114,26,124,3,106,1,83, + 0,100,1,83,0,100,1,83,0,41,2,122,108,70,105,110, + 100,32,109,111,100,117,108,101,32,110,97,109,101,100,32,105, + 110,32,116,104,101,32,114,101,103,105,115,116,114,121,46,10, + 10,32,32,32,32,32,32,32,32,84,104,105,115,32,109,101, + 116,104,111,100,32,105,115,32,100,101,112,114,101,99,97,116, + 101,100,46,32,32,85,115,101,32,101,120,101,99,95,109,111, + 100,117,108,101,40,41,32,105,110,115,116,101,97,100,46,10, + 10,32,32,32,32,32,32,32,32,78,41,2,114,178,0,0, + 0,114,124,0,0,0,41,4,114,168,0,0,0,114,123,0, + 0,0,114,37,0,0,0,114,162,0,0,0,114,4,0,0, + 0,114,4,0,0,0,114,6,0,0,0,218,11,102,105,110, + 100,95,109,111,100,117,108,101,129,2,0,0,115,8,0,0, + 0,0,7,12,1,8,1,6,2,122,33,87,105,110,100,111, + 119,115,82,101,103,105,115,116,114,121,70,105,110,100,101,114, + 46,102,105,110,100,95,109,111,100,117,108,101,41,2,78,78, + 41,1,78,41,12,114,109,0,0,0,114,108,0,0,0,114, + 110,0,0,0,114,111,0,0,0,114,172,0,0,0,114,171, + 0,0,0,114,170,0,0,0,218,11,99,108,97,115,115,109, + 101,116,104,111,100,114,169,0,0,0,114,175,0,0,0,114, + 178,0,0,0,114,179,0,0,0,114,4,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,166,0, + 0,0,79,2,0,0,115,20,0,0,0,8,2,4,3,4, + 3,4,2,4,2,12,7,12,15,2,1,12,15,2,1,114, + 166,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, + 0,2,0,0,0,64,0,0,0,115,48,0,0,0,101,0, 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0, 90,4,100,4,100,5,132,0,90,5,100,6,100,7,132,0, - 90,6,101,7,135,0,102,1,100,8,100,9,132,8,131,1, - 90,8,101,7,100,10,100,11,132,0,131,1,90,9,100,12, - 100,13,132,0,90,10,135,0,90,11,100,14,83,0,41,15, - 218,10,70,105,108,101,76,111,97,100,101,114,122,103,66,97, - 115,101,32,102,105,108,101,32,108,111,97,100,101,114,32,99, - 108,97,115,115,32,119,104,105,99,104,32,105,109,112,108,101, - 109,101,110,116,115,32,116,104,101,32,108,111,97,100,101,114, - 32,112,114,111,116,111,99,111,108,32,109,101,116,104,111,100, - 115,32,116,104,97,116,10,32,32,32,32,114,101,113,117,105, - 114,101,32,102,105,108,101,32,115,121,115,116,101,109,32,117, - 115,97,103,101,46,99,3,0,0,0,0,0,0,0,3,0, - 0,0,2,0,0,0,67,0,0,0,115,16,0,0,0,124, - 1,124,0,95,0,124,2,124,0,95,1,100,1,83,0,41, - 2,122,75,67,97,99,104,101,32,116,104,101,32,109,111,100, - 117,108,101,32,110,97,109,101,32,97,110,100,32,116,104,101, - 32,112,97,116,104,32,116,111,32,116,104,101,32,102,105,108, - 101,32,102,111,117,110,100,32,98,121,32,116,104,101,10,32, - 32,32,32,32,32,32,32,102,105,110,100,101,114,46,78,41, - 2,114,102,0,0,0,114,37,0,0,0,41,3,114,104,0, - 0,0,114,123,0,0,0,114,37,0,0,0,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,114,182,0,0,0, - 31,3,0,0,115,4,0,0,0,0,3,6,1,122,19,70, - 105,108,101,76,111,97,100,101,114,46,95,95,105,110,105,116, - 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, - 0,0,0,67,0,0,0,115,24,0,0,0,124,0,106,0, - 124,1,106,0,107,2,111,22,124,0,106,1,124,1,106,1, - 107,2,83,0,41,1,78,41,2,218,9,95,95,99,108,97, - 115,115,95,95,114,115,0,0,0,41,2,114,104,0,0,0, - 218,5,111,116,104,101,114,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,6,95,95,101,113,95,95,37,3, - 0,0,115,4,0,0,0,0,1,12,1,122,17,70,105,108, - 101,76,111,97,100,101,114,46,95,95,101,113,95,95,99,1, - 0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,67, - 0,0,0,115,20,0,0,0,116,0,124,0,106,1,131,1, - 116,0,124,0,106,2,131,1,65,0,83,0,41,1,78,41, - 3,218,4,104,97,115,104,114,102,0,0,0,114,37,0,0, - 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,218,8,95,95,104,97,115,104,95, - 95,41,3,0,0,115,2,0,0,0,0,1,122,19,70,105, - 108,101,76,111,97,100,101,114,46,95,95,104,97,115,104,95, - 95,99,2,0,0,0,0,0,0,0,2,0,0,0,3,0, - 0,0,3,0,0,0,115,16,0,0,0,116,0,116,1,124, - 0,131,2,106,2,124,1,131,1,83,0,41,1,122,100,76, - 111,97,100,32,97,32,109,111,100,117,108,101,32,102,114,111, - 109,32,97,32,102,105,108,101,46,10,10,32,32,32,32,32, - 32,32,32,84,104,105,115,32,109,101,116,104,111,100,32,105, - 115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,85, - 115,101,32,101,120,101,99,95,109,111,100,117,108,101,40,41, - 32,105,110,115,116,101,97,100,46,10,10,32,32,32,32,32, - 32,32,32,41,3,218,5,115,117,112,101,114,114,207,0,0, - 0,114,190,0,0,0,41,2,114,104,0,0,0,114,123,0, - 0,0,41,1,114,208,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,190,0,0,0,44,3,0,0,115,2,0,0, - 0,0,10,122,22,70,105,108,101,76,111,97,100,101,114,46, - 108,111,97,100,95,109,111,100,117,108,101,99,2,0,0,0, - 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, - 115,6,0,0,0,124,0,106,0,83,0,41,1,122,58,82, - 101,116,117,114,110,32,116,104,101,32,112,97,116,104,32,116, - 111,32,116,104,101,32,115,111,117,114,99,101,32,102,105,108, - 101,32,97,115,32,102,111,117,110,100,32,98,121,32,116,104, - 101,32,102,105,110,100,101,114,46,41,1,114,37,0,0,0, + 90,6,100,8,100,9,132,0,90,7,100,10,83,0,41,11, + 218,13,95,76,111,97,100,101,114,66,97,115,105,99,115,122, + 83,66,97,115,101,32,99,108,97,115,115,32,111,102,32,99, + 111,109,109,111,110,32,99,111,100,101,32,110,101,101,100,101, + 100,32,98,121,32,98,111,116,104,32,83,111,117,114,99,101, + 76,111,97,100,101,114,32,97,110,100,10,32,32,32,32,83, + 111,117,114,99,101,108,101,115,115,70,105,108,101,76,111,97, + 100,101,114,46,99,2,0,0,0,0,0,0,0,5,0,0, + 0,3,0,0,0,67,0,0,0,115,64,0,0,0,116,0, + 124,0,106,1,124,1,131,1,131,1,100,1,25,0,125,2, + 124,2,106,2,100,2,100,1,131,2,100,3,25,0,125,3, + 124,1,106,3,100,2,131,1,100,4,25,0,125,4,124,3, + 100,5,107,2,111,62,124,4,100,5,107,3,83,0,41,6, + 122,141,67,111,110,99,114,101,116,101,32,105,109,112,108,101, + 109,101,110,116,97,116,105,111,110,32,111,102,32,73,110,115, + 112,101,99,116,76,111,97,100,101,114,46,105,115,95,112,97, + 99,107,97,103,101,32,98,121,32,99,104,101,99,107,105,110, + 103,32,105,102,10,32,32,32,32,32,32,32,32,116,104,101, + 32,112,97,116,104,32,114,101,116,117,114,110,101,100,32,98, + 121,32,103,101,116,95,102,105,108,101,110,97,109,101,32,104, + 97,115,32,97,32,102,105,108,101,110,97,109,101,32,111,102, + 32,39,95,95,105,110,105,116,95,95,46,112,121,39,46,114, + 31,0,0,0,114,61,0,0,0,114,62,0,0,0,114,59, + 0,0,0,218,8,95,95,105,110,105,116,95,95,41,4,114, + 40,0,0,0,114,155,0,0,0,114,36,0,0,0,114,34, + 0,0,0,41,5,114,104,0,0,0,114,123,0,0,0,114, + 98,0,0,0,90,13,102,105,108,101,110,97,109,101,95,98, + 97,115,101,90,9,116,97,105,108,95,110,97,109,101,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,157,0, + 0,0,148,2,0,0,115,8,0,0,0,0,3,18,1,16, + 1,14,1,122,24,95,76,111,97,100,101,114,66,97,115,105, + 99,115,46,105,115,95,112,97,99,107,97,103,101,99,2,0, + 0,0,0,0,0,0,2,0,0,0,1,0,0,0,67,0, + 0,0,115,4,0,0,0,100,1,83,0,41,2,122,42,85, + 115,101,32,100,101,102,97,117,108,116,32,115,101,109,97,110, + 116,105,99,115,32,102,111,114,32,109,111,100,117,108,101,32, + 99,114,101,97,116,105,111,110,46,78,114,4,0,0,0,41, + 2,114,104,0,0,0,114,162,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,13,99,114,101,97, + 116,101,95,109,111,100,117,108,101,156,2,0,0,115,0,0, + 0,0,122,27,95,76,111,97,100,101,114,66,97,115,105,99, + 115,46,99,114,101,97,116,101,95,109,111,100,117,108,101,99, + 2,0,0,0,0,0,0,0,3,0,0,0,4,0,0,0, + 67,0,0,0,115,56,0,0,0,124,0,106,0,124,1,106, + 1,131,1,125,2,124,2,100,1,107,8,114,36,116,2,100, + 2,106,3,124,1,106,1,131,1,131,1,130,1,116,4,106, + 5,116,6,124,2,124,1,106,7,131,3,1,0,100,1,83, + 0,41,3,122,19,69,120,101,99,117,116,101,32,116,104,101, + 32,109,111,100,117,108,101,46,78,122,52,99,97,110,110,111, + 116,32,108,111,97,100,32,109,111,100,117,108,101,32,123,33, + 114,125,32,119,104,101,110,32,103,101,116,95,99,111,100,101, + 40,41,32,114,101,116,117,114,110,115,32,78,111,110,101,41, + 8,218,8,103,101,116,95,99,111,100,101,114,109,0,0,0, + 114,103,0,0,0,114,50,0,0,0,114,118,0,0,0,218, + 25,95,99,97,108,108,95,119,105,116,104,95,102,114,97,109, + 101,115,95,114,101,109,111,118,101,100,218,4,101,120,101,99, + 114,115,0,0,0,41,3,114,104,0,0,0,218,6,109,111, + 100,117,108,101,114,144,0,0,0,114,4,0,0,0,114,4, + 0,0,0,114,6,0,0,0,218,11,101,120,101,99,95,109, + 111,100,117,108,101,159,2,0,0,115,10,0,0,0,0,2, + 12,1,8,1,6,1,10,1,122,25,95,76,111,97,100,101, + 114,66,97,115,105,99,115,46,101,120,101,99,95,109,111,100, + 117,108,101,99,2,0,0,0,0,0,0,0,2,0,0,0, + 3,0,0,0,67,0,0,0,115,12,0,0,0,116,0,106, + 1,124,0,124,1,131,2,83,0,41,1,122,26,84,104,105, + 115,32,109,111,100,117,108,101,32,105,115,32,100,101,112,114, + 101,99,97,116,101,100,46,41,2,114,118,0,0,0,218,17, + 95,108,111,97,100,95,109,111,100,117,108,101,95,115,104,105, + 109,41,2,114,104,0,0,0,114,123,0,0,0,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,218,11,108,111, + 97,100,95,109,111,100,117,108,101,167,2,0,0,115,2,0, + 0,0,0,2,122,25,95,76,111,97,100,101,114,66,97,115, + 105,99,115,46,108,111,97,100,95,109,111,100,117,108,101,78, + 41,8,114,109,0,0,0,114,108,0,0,0,114,110,0,0, + 0,114,111,0,0,0,114,157,0,0,0,114,183,0,0,0, + 114,188,0,0,0,114,190,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,114,181, + 0,0,0,143,2,0,0,115,10,0,0,0,8,3,4,2, + 8,8,8,3,8,8,114,181,0,0,0,99,0,0,0,0, + 0,0,0,0,0,0,0,0,3,0,0,0,64,0,0,0, + 115,74,0,0,0,101,0,90,1,100,0,90,2,100,1,100, + 2,132,0,90,3,100,3,100,4,132,0,90,4,100,5,100, + 6,132,0,90,5,100,7,100,8,132,0,90,6,100,9,100, + 10,132,0,90,7,100,18,100,12,156,1,100,13,100,14,132, + 2,90,8,100,15,100,16,132,0,90,9,100,17,83,0,41, + 19,218,12,83,111,117,114,99,101,76,111,97,100,101,114,99, + 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, + 67,0,0,0,115,8,0,0,0,116,0,130,1,100,1,83, + 0,41,2,122,178,79,112,116,105,111,110,97,108,32,109,101, + 116,104,111,100,32,116,104,97,116,32,114,101,116,117,114,110, + 115,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105, + 111,110,32,116,105,109,101,32,40,97,110,32,105,110,116,41, + 32,102,111,114,32,116,104,101,10,32,32,32,32,32,32,32, + 32,115,112,101,99,105,102,105,101,100,32,112,97,116,104,44, + 32,119,104,101,114,101,32,112,97,116,104,32,105,115,32,97, + 32,115,116,114,46,10,10,32,32,32,32,32,32,32,32,82, + 97,105,115,101,115,32,73,79,69,114,114,111,114,32,119,104, + 101,110,32,116,104,101,32,112,97,116,104,32,99,97,110,110, + 111,116,32,98,101,32,104,97,110,100,108,101,100,46,10,32, + 32,32,32,32,32,32,32,78,41,1,218,7,73,79,69,114, + 114,111,114,41,2,114,104,0,0,0,114,37,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,10, + 112,97,116,104,95,109,116,105,109,101,174,2,0,0,115,2, + 0,0,0,0,6,122,23,83,111,117,114,99,101,76,111,97, + 100,101,114,46,112,97,116,104,95,109,116,105,109,101,99,2, + 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67, + 0,0,0,115,14,0,0,0,100,1,124,0,106,0,124,1, + 131,1,105,1,83,0,41,2,97,170,1,0,0,79,112,116, + 105,111,110,97,108,32,109,101,116,104,111,100,32,114,101,116, + 117,114,110,105,110,103,32,97,32,109,101,116,97,100,97,116, + 97,32,100,105,99,116,32,102,111,114,32,116,104,101,32,115, + 112,101,99,105,102,105,101,100,32,112,97,116,104,10,32,32, + 32,32,32,32,32,32,116,111,32,98,121,32,116,104,101,32, + 112,97,116,104,32,40,115,116,114,41,46,10,32,32,32,32, + 32,32,32,32,80,111,115,115,105,98,108,101,32,107,101,121, + 115,58,10,32,32,32,32,32,32,32,32,45,32,39,109,116, + 105,109,101,39,32,40,109,97,110,100,97,116,111,114,121,41, + 32,105,115,32,116,104,101,32,110,117,109,101,114,105,99,32, + 116,105,109,101,115,116,97,109,112,32,111,102,32,108,97,115, + 116,32,115,111,117,114,99,101,10,32,32,32,32,32,32,32, + 32,32,32,99,111,100,101,32,109,111,100,105,102,105,99,97, + 116,105,111,110,59,10,32,32,32,32,32,32,32,32,45,32, + 39,115,105,122,101,39,32,40,111,112,116,105,111,110,97,108, + 41,32,105,115,32,116,104,101,32,115,105,122,101,32,105,110, + 32,98,121,116,101,115,32,111,102,32,116,104,101,32,115,111, + 117,114,99,101,32,99,111,100,101,46,10,10,32,32,32,32, + 32,32,32,32,73,109,112,108,101,109,101,110,116,105,110,103, + 32,116,104,105,115,32,109,101,116,104,111,100,32,97,108,108, + 111,119,115,32,116,104,101,32,108,111,97,100,101,114,32,116, + 111,32,114,101,97,100,32,98,121,116,101,99,111,100,101,32, + 102,105,108,101,115,46,10,32,32,32,32,32,32,32,32,82, + 97,105,115,101,115,32,73,79,69,114,114,111,114,32,119,104, + 101,110,32,116,104,101,32,112,97,116,104,32,99,97,110,110, + 111,116,32,98,101,32,104,97,110,100,108,101,100,46,10,32, + 32,32,32,32,32,32,32,114,130,0,0,0,41,1,114,193, + 0,0,0,41,2,114,104,0,0,0,114,37,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,10, + 112,97,116,104,95,115,116,97,116,115,182,2,0,0,115,2, + 0,0,0,0,11,122,23,83,111,117,114,99,101,76,111,97, + 100,101,114,46,112,97,116,104,95,115,116,97,116,115,99,4, + 0,0,0,0,0,0,0,4,0,0,0,3,0,0,0,67, + 0,0,0,115,12,0,0,0,124,0,106,0,124,2,124,3, + 131,2,83,0,41,1,122,228,79,112,116,105,111,110,97,108, + 32,109,101,116,104,111,100,32,119,104,105,99,104,32,119,114, + 105,116,101,115,32,100,97,116,97,32,40,98,121,116,101,115, + 41,32,116,111,32,97,32,102,105,108,101,32,112,97,116,104, + 32,40,97,32,115,116,114,41,46,10,10,32,32,32,32,32, + 32,32,32,73,109,112,108,101,109,101,110,116,105,110,103,32, + 116,104,105,115,32,109,101,116,104,111,100,32,97,108,108,111, + 119,115,32,102,111,114,32,116,104,101,32,119,114,105,116,105, + 110,103,32,111,102,32,98,121,116,101,99,111,100,101,32,102, + 105,108,101,115,46,10,10,32,32,32,32,32,32,32,32,84, + 104,101,32,115,111,117,114,99,101,32,112,97,116,104,32,105, + 115,32,110,101,101,100,101,100,32,105,110,32,111,114,100,101, + 114,32,116,111,32,99,111,114,114,101,99,116,108,121,32,116, + 114,97,110,115,102,101,114,32,112,101,114,109,105,115,115,105, + 111,110,115,10,32,32,32,32,32,32,32,32,41,1,218,8, + 115,101,116,95,100,97,116,97,41,4,114,104,0,0,0,114, + 94,0,0,0,90,10,99,97,99,104,101,95,112,97,116,104, + 114,56,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,218,15,95,99,97,99,104,101,95,98,121,116, + 101,99,111,100,101,195,2,0,0,115,2,0,0,0,0,8, + 122,28,83,111,117,114,99,101,76,111,97,100,101,114,46,95, + 99,97,99,104,101,95,98,121,116,101,99,111,100,101,99,3, + 0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,67, + 0,0,0,115,4,0,0,0,100,1,83,0,41,2,122,150, + 79,112,116,105,111,110,97,108,32,109,101,116,104,111,100,32, + 119,104,105,99,104,32,119,114,105,116,101,115,32,100,97,116, + 97,32,40,98,121,116,101,115,41,32,116,111,32,97,32,102, + 105,108,101,32,112,97,116,104,32,40,97,32,115,116,114,41, + 46,10,10,32,32,32,32,32,32,32,32,73,109,112,108,101, + 109,101,110,116,105,110,103,32,116,104,105,115,32,109,101,116, + 104,111,100,32,97,108,108,111,119,115,32,102,111,114,32,116, + 104,101,32,119,114,105,116,105,110,103,32,111,102,32,98,121, + 116,101,99,111,100,101,32,102,105,108,101,115,46,10,32,32, + 32,32,32,32,32,32,78,114,4,0,0,0,41,3,114,104, + 0,0,0,114,37,0,0,0,114,56,0,0,0,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,114,195,0,0, + 0,205,2,0,0,115,0,0,0,0,122,21,83,111,117,114, + 99,101,76,111,97,100,101,114,46,115,101,116,95,100,97,116, + 97,99,2,0,0,0,0,0,0,0,5,0,0,0,16,0, + 0,0,67,0,0,0,115,82,0,0,0,124,0,106,0,124, + 1,131,1,125,2,121,14,124,0,106,1,124,2,131,1,125, + 3,87,0,110,48,4,0,116,2,107,10,114,72,1,0,125, + 4,1,0,122,20,116,3,100,1,124,1,100,2,141,2,124, + 4,130,2,87,0,89,0,100,3,100,3,125,4,126,4,88, + 0,110,2,88,0,116,4,124,3,131,1,83,0,41,4,122, + 52,67,111,110,99,114,101,116,101,32,105,109,112,108,101,109, + 101,110,116,97,116,105,111,110,32,111,102,32,73,110,115,112, + 101,99,116,76,111,97,100,101,114,46,103,101,116,95,115,111, + 117,114,99,101,46,122,39,115,111,117,114,99,101,32,110,111, + 116,32,97,118,97,105,108,97,98,108,101,32,116,104,114,111, + 117,103,104,32,103,101,116,95,100,97,116,97,40,41,41,1, + 114,102,0,0,0,78,41,5,114,155,0,0,0,218,8,103, + 101,116,95,100,97,116,97,114,42,0,0,0,114,103,0,0, + 0,114,153,0,0,0,41,5,114,104,0,0,0,114,123,0, + 0,0,114,37,0,0,0,114,151,0,0,0,218,3,101,120, + 99,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,10,103,101,116,95,115,111,117,114,99,101,212,2,0,0, + 115,14,0,0,0,0,2,10,1,2,1,14,1,16,1,4, + 1,28,1,122,23,83,111,117,114,99,101,76,111,97,100,101, + 114,46,103,101,116,95,115,111,117,114,99,101,114,31,0,0, + 0,41,1,218,9,95,111,112,116,105,109,105,122,101,99,3, + 0,0,0,1,0,0,0,4,0,0,0,8,0,0,0,67, + 0,0,0,115,22,0,0,0,116,0,106,1,116,2,124,1, + 124,2,100,1,100,2,124,3,100,3,141,6,83,0,41,4, + 122,130,82,101,116,117,114,110,32,116,104,101,32,99,111,100, + 101,32,111,98,106,101,99,116,32,99,111,109,112,105,108,101, + 100,32,102,114,111,109,32,115,111,117,114,99,101,46,10,10, + 32,32,32,32,32,32,32,32,84,104,101,32,39,100,97,116, + 97,39,32,97,114,103,117,109,101,110,116,32,99,97,110,32, + 98,101,32,97,110,121,32,111,98,106,101,99,116,32,116,121, + 112,101,32,116,104,97,116,32,99,111,109,112,105,108,101,40, + 41,32,115,117,112,112,111,114,116,115,46,10,32,32,32,32, + 32,32,32,32,114,186,0,0,0,84,41,2,218,12,100,111, + 110,116,95,105,110,104,101,114,105,116,114,72,0,0,0,41, + 3,114,118,0,0,0,114,185,0,0,0,218,7,99,111,109, + 112,105,108,101,41,4,114,104,0,0,0,114,56,0,0,0, + 114,37,0,0,0,114,200,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,218,14,115,111,117,114,99, + 101,95,116,111,95,99,111,100,101,222,2,0,0,115,4,0, + 0,0,0,5,12,1,122,27,83,111,117,114,99,101,76,111, + 97,100,101,114,46,115,111,117,114,99,101,95,116,111,95,99, + 111,100,101,99,2,0,0,0,0,0,0,0,10,0,0,0, + 43,0,0,0,67,0,0,0,115,94,1,0,0,124,0,106, + 0,124,1,131,1,125,2,100,1,125,3,121,12,116,1,124, + 2,131,1,125,4,87,0,110,24,4,0,116,2,107,10,114, + 50,1,0,1,0,1,0,100,1,125,4,89,0,110,162,88, + 0,121,14,124,0,106,3,124,2,131,1,125,5,87,0,110, + 20,4,0,116,4,107,10,114,86,1,0,1,0,1,0,89, + 0,110,126,88,0,116,5,124,5,100,2,25,0,131,1,125, + 3,121,14,124,0,106,6,124,4,131,1,125,6,87,0,110, + 20,4,0,116,7,107,10,114,134,1,0,1,0,1,0,89, + 0,110,78,88,0,121,20,116,8,124,6,124,5,124,1,124, + 4,100,3,141,4,125,7,87,0,110,24,4,0,116,9,116, + 10,102,2,107,10,114,180,1,0,1,0,1,0,89,0,110, + 32,88,0,116,11,106,12,100,4,124,4,124,2,131,3,1, + 0,116,13,124,7,124,1,124,4,124,2,100,5,141,4,83, + 0,124,0,106,6,124,2,131,1,125,8,124,0,106,14,124, + 8,124,2,131,2,125,9,116,11,106,12,100,6,124,2,131, + 2,1,0,116,15,106,16,12,0,144,1,114,90,124,4,100, + 1,107,9,144,1,114,90,124,3,100,1,107,9,144,1,114, + 90,116,17,124,9,124,3,116,18,124,8,131,1,131,3,125, + 6,121,30,124,0,106,19,124,2,124,4,124,6,131,3,1, + 0,116,11,106,12,100,7,124,4,131,2,1,0,87,0,110, + 22,4,0,116,2,107,10,144,1,114,88,1,0,1,0,1, + 0,89,0,110,2,88,0,124,9,83,0,41,8,122,190,67, + 111,110,99,114,101,116,101,32,105,109,112,108,101,109,101,110, + 116,97,116,105,111,110,32,111,102,32,73,110,115,112,101,99, + 116,76,111,97,100,101,114,46,103,101,116,95,99,111,100,101, + 46,10,10,32,32,32,32,32,32,32,32,82,101,97,100,105, + 110,103,32,111,102,32,98,121,116,101,99,111,100,101,32,114, + 101,113,117,105,114,101,115,32,112,97,116,104,95,115,116,97, + 116,115,32,116,111,32,98,101,32,105,109,112,108,101,109,101, + 110,116,101,100,46,32,84,111,32,119,114,105,116,101,10,32, + 32,32,32,32,32,32,32,98,121,116,101,99,111,100,101,44, + 32,115,101,116,95,100,97,116,97,32,109,117,115,116,32,97, + 108,115,111,32,98,101,32,105,109,112,108,101,109,101,110,116, + 101,100,46,10,10,32,32,32,32,32,32,32,32,78,114,130, + 0,0,0,41,3,114,136,0,0,0,114,102,0,0,0,114, + 37,0,0,0,122,13,123,125,32,109,97,116,99,104,101,115, + 32,123,125,41,3,114,102,0,0,0,114,93,0,0,0,114, + 94,0,0,0,122,19,99,111,100,101,32,111,98,106,101,99, + 116,32,102,114,111,109,32,123,125,122,10,119,114,111,116,101, + 32,123,33,114,125,41,20,114,155,0,0,0,114,83,0,0, + 0,114,70,0,0,0,114,194,0,0,0,114,192,0,0,0, + 114,16,0,0,0,114,197,0,0,0,114,42,0,0,0,114, + 139,0,0,0,114,103,0,0,0,114,134,0,0,0,114,118, + 0,0,0,114,133,0,0,0,114,145,0,0,0,114,203,0, + 0,0,114,8,0,0,0,218,19,100,111,110,116,95,119,114, + 105,116,101,95,98,121,116,101,99,111,100,101,114,148,0,0, + 0,114,33,0,0,0,114,196,0,0,0,41,10,114,104,0, + 0,0,114,123,0,0,0,114,94,0,0,0,114,137,0,0, + 0,114,93,0,0,0,218,2,115,116,114,56,0,0,0,218, + 10,98,121,116,101,115,95,100,97,116,97,114,151,0,0,0, + 90,11,99,111,100,101,95,111,98,106,101,99,116,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,114,184,0,0, + 0,230,2,0,0,115,78,0,0,0,0,7,10,1,4,1, + 2,1,12,1,14,1,10,2,2,1,14,1,14,1,6,2, + 12,1,2,1,14,1,14,1,6,2,2,1,4,1,4,1, + 12,1,18,1,6,2,8,1,6,1,6,1,2,1,8,1, + 10,1,12,1,12,1,20,1,10,1,6,1,10,1,2,1, + 14,1,16,1,16,1,6,1,122,21,83,111,117,114,99,101, + 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,78, + 114,91,0,0,0,41,10,114,109,0,0,0,114,108,0,0, + 0,114,110,0,0,0,114,193,0,0,0,114,194,0,0,0, + 114,196,0,0,0,114,195,0,0,0,114,199,0,0,0,114, + 203,0,0,0,114,184,0,0,0,114,4,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,191,0, + 0,0,172,2,0,0,115,14,0,0,0,8,2,8,8,8, + 13,8,10,8,7,8,10,14,8,114,191,0,0,0,99,0, + 0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0, + 0,0,0,115,80,0,0,0,101,0,90,1,100,0,90,2, + 100,1,90,3,100,2,100,3,132,0,90,4,100,4,100,5, + 132,0,90,5,100,6,100,7,132,0,90,6,101,7,135,0, + 102,1,100,8,100,9,132,8,131,1,90,8,101,7,100,10, + 100,11,132,0,131,1,90,9,100,12,100,13,132,0,90,10, + 135,0,90,11,100,14,83,0,41,15,218,10,70,105,108,101, + 76,111,97,100,101,114,122,103,66,97,115,101,32,102,105,108, + 101,32,108,111,97,100,101,114,32,99,108,97,115,115,32,119, + 104,105,99,104,32,105,109,112,108,101,109,101,110,116,115,32, + 116,104,101,32,108,111,97,100,101,114,32,112,114,111,116,111, + 99,111,108,32,109,101,116,104,111,100,115,32,116,104,97,116, + 10,32,32,32,32,114,101,113,117,105,114,101,32,102,105,108, + 101,32,115,121,115,116,101,109,32,117,115,97,103,101,46,99, + 3,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0, + 67,0,0,0,115,16,0,0,0,124,1,124,0,95,0,124, + 2,124,0,95,1,100,1,83,0,41,2,122,75,67,97,99, + 104,101,32,116,104,101,32,109,111,100,117,108,101,32,110,97, + 109,101,32,97,110,100,32,116,104,101,32,112,97,116,104,32, + 116,111,32,116,104,101,32,102,105,108,101,32,102,111,117,110, + 100,32,98,121,32,116,104,101,10,32,32,32,32,32,32,32, + 32,102,105,110,100,101,114,46,78,41,2,114,102,0,0,0, + 114,37,0,0,0,41,3,114,104,0,0,0,114,123,0,0, + 0,114,37,0,0,0,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,114,182,0,0,0,31,3,0,0,115,4, + 0,0,0,0,3,6,1,122,19,70,105,108,101,76,111,97, + 100,101,114,46,95,95,105,110,105,116,95,95,99,2,0,0, + 0,0,0,0,0,2,0,0,0,2,0,0,0,67,0,0, + 0,115,24,0,0,0,124,0,106,0,124,1,106,0,107,2, + 111,22,124,0,106,1,124,1,106,1,107,2,83,0,41,1, + 78,41,2,218,9,95,95,99,108,97,115,115,95,95,114,115, + 0,0,0,41,2,114,104,0,0,0,218,5,111,116,104,101, + 114,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,6,95,95,101,113,95,95,37,3,0,0,115,4,0,0, + 0,0,1,12,1,122,17,70,105,108,101,76,111,97,100,101, + 114,46,95,95,101,113,95,95,99,1,0,0,0,0,0,0, + 0,1,0,0,0,3,0,0,0,67,0,0,0,115,20,0, + 0,0,116,0,124,0,106,1,131,1,116,0,124,0,106,2, + 131,1,65,0,83,0,41,1,78,41,3,218,4,104,97,115, + 104,114,102,0,0,0,114,37,0,0,0,41,1,114,104,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,218,8,95,95,104,97,115,104,95,95,41,3,0,0,115, + 2,0,0,0,0,1,122,19,70,105,108,101,76,111,97,100, + 101,114,46,95,95,104,97,115,104,95,95,99,2,0,0,0, + 0,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0, + 115,16,0,0,0,116,0,116,1,124,0,131,2,106,2,124, + 1,131,1,83,0,41,1,122,100,76,111,97,100,32,97,32, + 109,111,100,117,108,101,32,102,114,111,109,32,97,32,102,105, + 108,101,46,10,10,32,32,32,32,32,32,32,32,84,104,105, + 115,32,109,101,116,104,111,100,32,105,115,32,100,101,112,114, + 101,99,97,116,101,100,46,32,32,85,115,101,32,101,120,101, + 99,95,109,111,100,117,108,101,40,41,32,105,110,115,116,101, + 97,100,46,10,10,32,32,32,32,32,32,32,32,41,3,218, + 5,115,117,112,101,114,114,207,0,0,0,114,190,0,0,0, + 41,2,114,104,0,0,0,114,123,0,0,0,41,1,114,208, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,190,0, + 0,0,44,3,0,0,115,2,0,0,0,0,10,122,22,70, + 105,108,101,76,111,97,100,101,114,46,108,111,97,100,95,109, + 111,100,117,108,101,99,2,0,0,0,0,0,0,0,2,0, + 0,0,1,0,0,0,67,0,0,0,115,6,0,0,0,124, + 0,106,0,83,0,41,1,122,58,82,101,116,117,114,110,32, + 116,104,101,32,112,97,116,104,32,116,111,32,116,104,101,32, + 115,111,117,114,99,101,32,102,105,108,101,32,97,115,32,102, + 111,117,110,100,32,98,121,32,116,104,101,32,102,105,110,100, + 101,114,46,41,1,114,37,0,0,0,41,2,114,104,0,0, + 0,114,123,0,0,0,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,114,155,0,0,0,56,3,0,0,115,2, + 0,0,0,0,3,122,23,70,105,108,101,76,111,97,100,101, + 114,46,103,101,116,95,102,105,108,101,110,97,109,101,99,2, + 0,0,0,0,0,0,0,3,0,0,0,9,0,0,0,67, + 0,0,0,115,32,0,0,0,116,0,106,1,124,1,100,1, + 131,2,143,10,125,2,124,2,106,2,131,0,83,0,81,0, + 82,0,88,0,100,2,83,0,41,3,122,39,82,101,116,117, + 114,110,32,116,104,101,32,100,97,116,97,32,102,114,111,109, + 32,112,97,116,104,32,97,115,32,114,97,119,32,98,121,116, + 101,115,46,218,1,114,78,41,3,114,52,0,0,0,114,53, + 0,0,0,90,4,114,101,97,100,41,3,114,104,0,0,0, + 114,37,0,0,0,114,57,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,114,197,0,0,0,61,3, + 0,0,115,4,0,0,0,0,2,14,1,122,19,70,105,108, + 101,76,111,97,100,101,114,46,103,101,116,95,100,97,116,97, + 78,41,12,114,109,0,0,0,114,108,0,0,0,114,110,0, + 0,0,114,111,0,0,0,114,182,0,0,0,114,210,0,0, + 0,114,212,0,0,0,114,120,0,0,0,114,190,0,0,0, + 114,155,0,0,0,114,197,0,0,0,90,13,95,95,99,108, + 97,115,115,99,101,108,108,95,95,114,4,0,0,0,114,4, + 0,0,0,41,1,114,208,0,0,0,114,6,0,0,0,114, + 207,0,0,0,26,3,0,0,115,14,0,0,0,8,3,4, + 2,8,6,8,4,8,3,16,12,12,5,114,207,0,0,0, + 99,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0, + 0,64,0,0,0,115,46,0,0,0,101,0,90,1,100,0, + 90,2,100,1,90,3,100,2,100,3,132,0,90,4,100,4, + 100,5,132,0,90,5,100,6,100,7,156,1,100,8,100,9, + 132,2,90,6,100,10,83,0,41,11,218,16,83,111,117,114, + 99,101,70,105,108,101,76,111,97,100,101,114,122,62,67,111, + 110,99,114,101,116,101,32,105,109,112,108,101,109,101,110,116, + 97,116,105,111,110,32,111,102,32,83,111,117,114,99,101,76, + 111,97,100,101,114,32,117,115,105,110,103,32,116,104,101,32, + 102,105,108,101,32,115,121,115,116,101,109,46,99,2,0,0, + 0,0,0,0,0,3,0,0,0,3,0,0,0,67,0,0, + 0,115,22,0,0,0,116,0,124,1,131,1,125,2,124,2, + 106,1,124,2,106,2,100,1,156,2,83,0,41,2,122,33, + 82,101,116,117,114,110,32,116,104,101,32,109,101,116,97,100, + 97,116,97,32,102,111,114,32,116,104,101,32,112,97,116,104, + 46,41,2,114,130,0,0,0,114,131,0,0,0,41,3,114, + 41,0,0,0,218,8,115,116,95,109,116,105,109,101,90,7, + 115,116,95,115,105,122,101,41,3,114,104,0,0,0,114,37, + 0,0,0,114,205,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,194,0,0,0,71,3,0,0, + 115,4,0,0,0,0,2,8,1,122,27,83,111,117,114,99, + 101,70,105,108,101,76,111,97,100,101,114,46,112,97,116,104, + 95,115,116,97,116,115,99,4,0,0,0,0,0,0,0,5, + 0,0,0,5,0,0,0,67,0,0,0,115,24,0,0,0, + 116,0,124,1,131,1,125,4,124,0,106,1,124,2,124,3, + 124,4,100,1,141,3,83,0,41,2,78,41,1,218,5,95, + 109,111,100,101,41,2,114,101,0,0,0,114,195,0,0,0, + 41,5,114,104,0,0,0,114,94,0,0,0,114,93,0,0, + 0,114,56,0,0,0,114,44,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,196,0,0,0,76, + 3,0,0,115,4,0,0,0,0,2,8,1,122,32,83,111, + 117,114,99,101,70,105,108,101,76,111,97,100,101,114,46,95, + 99,97,99,104,101,95,98,121,116,101,99,111,100,101,105,182, + 1,0,0,41,1,114,217,0,0,0,99,3,0,0,0,1, + 0,0,0,9,0,0,0,17,0,0,0,67,0,0,0,115, + 250,0,0,0,116,0,124,1,131,1,92,2,125,4,125,5, + 103,0,125,6,120,40,124,4,114,56,116,1,124,4,131,1, + 12,0,114,56,116,0,124,4,131,1,92,2,125,4,125,7, + 124,6,106,2,124,7,131,1,1,0,113,18,87,0,120,108, + 116,3,124,6,131,1,68,0,93,96,125,7,116,4,124,4, + 124,7,131,2,125,4,121,14,116,5,106,6,124,4,131,1, + 1,0,87,0,113,68,4,0,116,7,107,10,114,118,1,0, + 1,0,1,0,119,68,89,0,113,68,4,0,116,8,107,10, + 114,162,1,0,125,8,1,0,122,18,116,9,106,10,100,1, + 124,4,124,8,131,3,1,0,100,2,83,0,100,2,125,8, + 126,8,88,0,113,68,88,0,113,68,87,0,121,28,116,11, + 124,1,124,2,124,3,131,3,1,0,116,9,106,10,100,3, + 124,1,131,2,1,0,87,0,110,48,4,0,116,8,107,10, + 114,244,1,0,125,8,1,0,122,20,116,9,106,10,100,1, + 124,1,124,8,131,3,1,0,87,0,89,0,100,2,100,2, + 125,8,126,8,88,0,110,2,88,0,100,2,83,0,41,4, + 122,27,87,114,105,116,101,32,98,121,116,101,115,32,100,97, + 116,97,32,116,111,32,97,32,102,105,108,101,46,122,27,99, + 111,117,108,100,32,110,111,116,32,99,114,101,97,116,101,32, + 123,33,114,125,58,32,123,33,114,125,78,122,12,99,114,101, + 97,116,101,100,32,123,33,114,125,41,12,114,40,0,0,0, + 114,48,0,0,0,114,161,0,0,0,114,35,0,0,0,114, + 30,0,0,0,114,3,0,0,0,90,5,109,107,100,105,114, + 218,15,70,105,108,101,69,120,105,115,116,115,69,114,114,111, + 114,114,42,0,0,0,114,118,0,0,0,114,133,0,0,0, + 114,58,0,0,0,41,9,114,104,0,0,0,114,37,0,0, + 0,114,56,0,0,0,114,217,0,0,0,218,6,112,97,114, + 101,110,116,114,98,0,0,0,114,29,0,0,0,114,25,0, + 0,0,114,198,0,0,0,114,4,0,0,0,114,4,0,0, + 0,114,6,0,0,0,114,195,0,0,0,81,3,0,0,115, + 42,0,0,0,0,2,12,1,4,2,16,1,12,1,14,2, + 14,1,10,1,2,1,14,1,14,2,6,1,16,3,6,1, + 8,1,20,1,2,1,12,1,16,1,16,2,8,1,122,25, + 83,111,117,114,99,101,70,105,108,101,76,111,97,100,101,114, + 46,115,101,116,95,100,97,116,97,78,41,7,114,109,0,0, + 0,114,108,0,0,0,114,110,0,0,0,114,111,0,0,0, + 114,194,0,0,0,114,196,0,0,0,114,195,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,114,215,0,0,0,67,3,0,0,115,8,0,0, + 0,8,2,4,2,8,5,8,5,114,215,0,0,0,99,0, + 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,64, + 0,0,0,115,32,0,0,0,101,0,90,1,100,0,90,2, + 100,1,90,3,100,2,100,3,132,0,90,4,100,4,100,5, + 132,0,90,5,100,6,83,0,41,7,218,20,83,111,117,114, + 99,101,108,101,115,115,70,105,108,101,76,111,97,100,101,114, + 122,45,76,111,97,100,101,114,32,119,104,105,99,104,32,104, + 97,110,100,108,101,115,32,115,111,117,114,99,101,108,101,115, + 115,32,102,105,108,101,32,105,109,112,111,114,116,115,46,99, + 2,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0, + 67,0,0,0,115,48,0,0,0,124,0,106,0,124,1,131, + 1,125,2,124,0,106,1,124,2,131,1,125,3,116,2,124, + 3,124,1,124,2,100,1,141,3,125,4,116,3,124,4,124, + 1,124,2,100,2,141,3,83,0,41,3,78,41,2,114,102, + 0,0,0,114,37,0,0,0,41,2,114,102,0,0,0,114, + 93,0,0,0,41,4,114,155,0,0,0,114,197,0,0,0, + 114,139,0,0,0,114,145,0,0,0,41,5,114,104,0,0, + 0,114,123,0,0,0,114,37,0,0,0,114,56,0,0,0, + 114,206,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,114,184,0,0,0,116,3,0,0,115,8,0, + 0,0,0,1,10,1,10,1,14,1,122,29,83,111,117,114, + 99,101,108,101,115,115,70,105,108,101,76,111,97,100,101,114, + 46,103,101,116,95,99,111,100,101,99,2,0,0,0,0,0, + 0,0,2,0,0,0,1,0,0,0,67,0,0,0,115,4, + 0,0,0,100,1,83,0,41,2,122,39,82,101,116,117,114, + 110,32,78,111,110,101,32,97,115,32,116,104,101,114,101,32, + 105,115,32,110,111,32,115,111,117,114,99,101,32,99,111,100, + 101,46,78,114,4,0,0,0,41,2,114,104,0,0,0,114, + 123,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,114,199,0,0,0,122,3,0,0,115,2,0,0, + 0,0,2,122,31,83,111,117,114,99,101,108,101,115,115,70, + 105,108,101,76,111,97,100,101,114,46,103,101,116,95,115,111, + 117,114,99,101,78,41,6,114,109,0,0,0,114,108,0,0, + 0,114,110,0,0,0,114,111,0,0,0,114,184,0,0,0, + 114,199,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,114,220,0,0,0,112,3, + 0,0,115,6,0,0,0,8,2,4,2,8,6,114,220,0, + 0,0,99,0,0,0,0,0,0,0,0,0,0,0,0,3, + 0,0,0,64,0,0,0,115,92,0,0,0,101,0,90,1, + 100,0,90,2,100,1,90,3,100,2,100,3,132,0,90,4, + 100,4,100,5,132,0,90,5,100,6,100,7,132,0,90,6, + 100,8,100,9,132,0,90,7,100,10,100,11,132,0,90,8, + 100,12,100,13,132,0,90,9,100,14,100,15,132,0,90,10, + 100,16,100,17,132,0,90,11,101,12,100,18,100,19,132,0, + 131,1,90,13,100,20,83,0,41,21,218,19,69,120,116,101, + 110,115,105,111,110,70,105,108,101,76,111,97,100,101,114,122, + 93,76,111,97,100,101,114,32,102,111,114,32,101,120,116,101, + 110,115,105,111,110,32,109,111,100,117,108,101,115,46,10,10, + 32,32,32,32,84,104,101,32,99,111,110,115,116,114,117,99, + 116,111,114,32,105,115,32,100,101,115,105,103,110,101,100,32, + 116,111,32,119,111,114,107,32,119,105,116,104,32,70,105,108, + 101,70,105,110,100,101,114,46,10,10,32,32,32,32,99,3, + 0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,67, + 0,0,0,115,16,0,0,0,124,1,124,0,95,0,124,2, + 124,0,95,1,100,0,83,0,41,1,78,41,2,114,102,0, + 0,0,114,37,0,0,0,41,3,114,104,0,0,0,114,102, + 0,0,0,114,37,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,182,0,0,0,139,3,0,0, + 115,4,0,0,0,0,1,6,1,122,28,69,120,116,101,110, + 115,105,111,110,70,105,108,101,76,111,97,100,101,114,46,95, + 95,105,110,105,116,95,95,99,2,0,0,0,0,0,0,0, + 2,0,0,0,2,0,0,0,67,0,0,0,115,24,0,0, + 0,124,0,106,0,124,1,106,0,107,2,111,22,124,0,106, + 1,124,1,106,1,107,2,83,0,41,1,78,41,2,114,208, + 0,0,0,114,115,0,0,0,41,2,114,104,0,0,0,114, + 209,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,114,210,0,0,0,143,3,0,0,115,4,0,0, + 0,0,1,12,1,122,26,69,120,116,101,110,115,105,111,110, + 70,105,108,101,76,111,97,100,101,114,46,95,95,101,113,95, + 95,99,1,0,0,0,0,0,0,0,1,0,0,0,3,0, + 0,0,67,0,0,0,115,20,0,0,0,116,0,124,0,106, + 1,131,1,116,0,124,0,106,2,131,1,65,0,83,0,41, + 1,78,41,3,114,211,0,0,0,114,102,0,0,0,114,37, + 0,0,0,41,1,114,104,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,114,212,0,0,0,147,3, + 0,0,115,2,0,0,0,0,1,122,28,69,120,116,101,110, + 115,105,111,110,70,105,108,101,76,111,97,100,101,114,46,95, + 95,104,97,115,104,95,95,99,2,0,0,0,0,0,0,0, + 3,0,0,0,4,0,0,0,67,0,0,0,115,36,0,0, + 0,116,0,106,1,116,2,106,3,124,1,131,2,125,2,116, + 0,106,4,100,1,124,1,106,5,124,0,106,6,131,3,1, + 0,124,2,83,0,41,2,122,38,67,114,101,97,116,101,32, + 97,110,32,117,110,105,116,105,97,108,105,122,101,100,32,101, + 120,116,101,110,115,105,111,110,32,109,111,100,117,108,101,122, + 38,101,120,116,101,110,115,105,111,110,32,109,111,100,117,108, + 101,32,123,33,114,125,32,108,111,97,100,101,100,32,102,114, + 111,109,32,123,33,114,125,41,7,114,118,0,0,0,114,185, + 0,0,0,114,143,0,0,0,90,14,99,114,101,97,116,101, + 95,100,121,110,97,109,105,99,114,133,0,0,0,114,102,0, + 0,0,114,37,0,0,0,41,3,114,104,0,0,0,114,162, + 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,183,0,0,0,150,3,0,0, + 115,10,0,0,0,0,2,4,1,10,1,6,1,12,1,122, + 33,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, + 97,100,101,114,46,99,114,101,97,116,101,95,109,111,100,117, + 108,101,99,2,0,0,0,0,0,0,0,2,0,0,0,4, + 0,0,0,67,0,0,0,115,36,0,0,0,116,0,106,1, + 116,2,106,3,124,1,131,2,1,0,116,0,106,4,100,1, + 124,0,106,5,124,0,106,6,131,3,1,0,100,2,83,0, + 41,3,122,30,73,110,105,116,105,97,108,105,122,101,32,97, + 110,32,101,120,116,101,110,115,105,111,110,32,109,111,100,117, + 108,101,122,40,101,120,116,101,110,115,105,111,110,32,109,111, + 100,117,108,101,32,123,33,114,125,32,101,120,101,99,117,116, + 101,100,32,102,114,111,109,32,123,33,114,125,78,41,7,114, + 118,0,0,0,114,185,0,0,0,114,143,0,0,0,90,12, + 101,120,101,99,95,100,121,110,97,109,105,99,114,133,0,0, + 0,114,102,0,0,0,114,37,0,0,0,41,2,114,104,0, + 0,0,114,187,0,0,0,114,4,0,0,0,114,4,0,0, + 0,114,6,0,0,0,114,188,0,0,0,158,3,0,0,115, + 6,0,0,0,0,2,14,1,6,1,122,31,69,120,116,101, + 110,115,105,111,110,70,105,108,101,76,111,97,100,101,114,46, + 101,120,101,99,95,109,111,100,117,108,101,99,2,0,0,0, + 0,0,0,0,2,0,0,0,4,0,0,0,3,0,0,0, + 115,36,0,0,0,116,0,124,0,106,1,131,1,100,1,25, + 0,137,0,116,2,135,0,102,1,100,2,100,3,132,8,116, + 3,68,0,131,1,131,1,83,0,41,4,122,49,82,101,116, + 117,114,110,32,84,114,117,101,32,105,102,32,116,104,101,32, + 101,120,116,101,110,115,105,111,110,32,109,111,100,117,108,101, + 32,105,115,32,97,32,112,97,99,107,97,103,101,46,114,31, + 0,0,0,99,1,0,0,0,0,0,0,0,2,0,0,0, + 4,0,0,0,51,0,0,0,115,26,0,0,0,124,0,93, + 18,125,1,136,0,100,0,124,1,23,0,107,2,86,0,1, + 0,113,2,100,1,83,0,41,2,114,182,0,0,0,78,114, + 4,0,0,0,41,2,114,24,0,0,0,218,6,115,117,102, + 102,105,120,41,1,218,9,102,105,108,101,95,110,97,109,101, + 114,4,0,0,0,114,6,0,0,0,250,9,60,103,101,110, + 101,120,112,114,62,167,3,0,0,115,2,0,0,0,4,1, + 122,49,69,120,116,101,110,115,105,111,110,70,105,108,101,76, + 111,97,100,101,114,46,105,115,95,112,97,99,107,97,103,101, + 46,60,108,111,99,97,108,115,62,46,60,103,101,110,101,120, + 112,114,62,41,4,114,40,0,0,0,114,37,0,0,0,218, + 3,97,110,121,218,18,69,88,84,69,78,83,73,79,78,95, + 83,85,70,70,73,88,69,83,41,2,114,104,0,0,0,114, + 123,0,0,0,114,4,0,0,0,41,1,114,223,0,0,0, + 114,6,0,0,0,114,157,0,0,0,164,3,0,0,115,6, + 0,0,0,0,2,14,1,12,1,122,30,69,120,116,101,110, + 115,105,111,110,70,105,108,101,76,111,97,100,101,114,46,105, + 115,95,112,97,99,107,97,103,101,99,2,0,0,0,0,0, + 0,0,2,0,0,0,1,0,0,0,67,0,0,0,115,4, + 0,0,0,100,1,83,0,41,2,122,63,82,101,116,117,114, + 110,32,78,111,110,101,32,97,115,32,97,110,32,101,120,116, + 101,110,115,105,111,110,32,109,111,100,117,108,101,32,99,97, + 110,110,111,116,32,99,114,101,97,116,101,32,97,32,99,111, + 100,101,32,111,98,106,101,99,116,46,78,114,4,0,0,0, 41,2,114,104,0,0,0,114,123,0,0,0,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,114,155,0,0,0, - 56,3,0,0,115,2,0,0,0,0,3,122,23,70,105,108, - 101,76,111,97,100,101,114,46,103,101,116,95,102,105,108,101, - 110,97,109,101,99,2,0,0,0,0,0,0,0,3,0,0, - 0,9,0,0,0,67,0,0,0,115,32,0,0,0,116,0, - 106,1,124,1,100,1,131,2,143,10,125,2,124,2,106,2, - 131,0,83,0,81,0,82,0,88,0,100,2,83,0,41,3, - 122,39,82,101,116,117,114,110,32,116,104,101,32,100,97,116, - 97,32,102,114,111,109,32,112,97,116,104,32,97,115,32,114, - 97,119,32,98,121,116,101,115,46,218,1,114,78,41,3,114, - 52,0,0,0,114,53,0,0,0,90,4,114,101,97,100,41, - 3,114,104,0,0,0,114,37,0,0,0,114,57,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 197,0,0,0,61,3,0,0,115,4,0,0,0,0,2,14, - 1,122,19,70,105,108,101,76,111,97,100,101,114,46,103,101, - 116,95,100,97,116,97,78,41,12,114,109,0,0,0,114,108, - 0,0,0,114,110,0,0,0,114,111,0,0,0,114,182,0, - 0,0,114,210,0,0,0,114,212,0,0,0,114,120,0,0, - 0,114,190,0,0,0,114,155,0,0,0,114,197,0,0,0, - 90,13,95,95,99,108,97,115,115,99,101,108,108,95,95,114, - 4,0,0,0,114,4,0,0,0,41,1,114,208,0,0,0, - 114,6,0,0,0,114,207,0,0,0,26,3,0,0,115,14, - 0,0,0,8,3,4,2,8,6,8,4,8,3,16,12,12, - 5,114,207,0,0,0,99,0,0,0,0,0,0,0,0,0, - 0,0,0,3,0,0,0,64,0,0,0,115,46,0,0,0, - 101,0,90,1,100,0,90,2,100,1,90,3,100,2,100,3, - 132,0,90,4,100,4,100,5,132,0,90,5,100,6,100,7, - 156,1,100,8,100,9,132,2,90,6,100,10,83,0,41,11, - 218,16,83,111,117,114,99,101,70,105,108,101,76,111,97,100, - 101,114,122,62,67,111,110,99,114,101,116,101,32,105,109,112, - 108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,83, - 111,117,114,99,101,76,111,97,100,101,114,32,117,115,105,110, - 103,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101, - 109,46,99,2,0,0,0,0,0,0,0,3,0,0,0,3, - 0,0,0,67,0,0,0,115,22,0,0,0,116,0,124,1, - 131,1,125,2,124,2,106,1,124,2,106,2,100,1,156,2, - 83,0,41,2,122,33,82,101,116,117,114,110,32,116,104,101, - 32,109,101,116,97,100,97,116,97,32,102,111,114,32,116,104, - 101,32,112,97,116,104,46,41,2,114,130,0,0,0,114,131, - 0,0,0,41,3,114,41,0,0,0,218,8,115,116,95,109, - 116,105,109,101,90,7,115,116,95,115,105,122,101,41,3,114, - 104,0,0,0,114,37,0,0,0,114,205,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,194,0, - 0,0,71,3,0,0,115,4,0,0,0,0,2,8,1,122, - 27,83,111,117,114,99,101,70,105,108,101,76,111,97,100,101, - 114,46,112,97,116,104,95,115,116,97,116,115,99,4,0,0, - 0,0,0,0,0,5,0,0,0,5,0,0,0,67,0,0, - 0,115,24,0,0,0,116,0,124,1,131,1,125,4,124,0, - 106,1,124,2,124,3,124,4,100,1,141,3,83,0,41,2, - 78,41,1,218,5,95,109,111,100,101,41,2,114,101,0,0, - 0,114,195,0,0,0,41,5,114,104,0,0,0,114,94,0, - 0,0,114,93,0,0,0,114,56,0,0,0,114,44,0,0, - 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,196,0,0,0,76,3,0,0,115,4,0,0,0,0,2, - 8,1,122,32,83,111,117,114,99,101,70,105,108,101,76,111, - 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, - 99,111,100,101,105,182,1,0,0,41,1,114,217,0,0,0, - 99,3,0,0,0,1,0,0,0,9,0,0,0,17,0,0, - 0,67,0,0,0,115,250,0,0,0,116,0,124,1,131,1, - 92,2,125,4,125,5,103,0,125,6,120,40,124,4,114,56, - 116,1,124,4,131,1,12,0,114,56,116,0,124,4,131,1, - 92,2,125,4,125,7,124,6,106,2,124,7,131,1,1,0, - 113,18,87,0,120,108,116,3,124,6,131,1,68,0,93,96, - 125,7,116,4,124,4,124,7,131,2,125,4,121,14,116,5, - 106,6,124,4,131,1,1,0,87,0,113,68,4,0,116,7, - 107,10,114,118,1,0,1,0,1,0,119,68,89,0,113,68, - 4,0,116,8,107,10,114,162,1,0,125,8,1,0,122,18, - 116,9,106,10,100,1,124,4,124,8,131,3,1,0,100,2, - 83,0,100,2,125,8,126,8,88,0,113,68,88,0,113,68, - 87,0,121,28,116,11,124,1,124,2,124,3,131,3,1,0, - 116,9,106,10,100,3,124,1,131,2,1,0,87,0,110,48, - 4,0,116,8,107,10,114,244,1,0,125,8,1,0,122,20, - 116,9,106,10,100,1,124,1,124,8,131,3,1,0,87,0, - 89,0,100,2,100,2,125,8,126,8,88,0,110,2,88,0, - 100,2,83,0,41,4,122,27,87,114,105,116,101,32,98,121, - 116,101,115,32,100,97,116,97,32,116,111,32,97,32,102,105, - 108,101,46,122,27,99,111,117,108,100,32,110,111,116,32,99, - 114,101,97,116,101,32,123,33,114,125,58,32,123,33,114,125, - 78,122,12,99,114,101,97,116,101,100,32,123,33,114,125,41, - 12,114,40,0,0,0,114,48,0,0,0,114,161,0,0,0, - 114,35,0,0,0,114,30,0,0,0,114,3,0,0,0,90, - 5,109,107,100,105,114,218,15,70,105,108,101,69,120,105,115, - 116,115,69,114,114,111,114,114,42,0,0,0,114,118,0,0, - 0,114,133,0,0,0,114,58,0,0,0,41,9,114,104,0, - 0,0,114,37,0,0,0,114,56,0,0,0,114,217,0,0, - 0,218,6,112,97,114,101,110,116,114,98,0,0,0,114,29, - 0,0,0,114,25,0,0,0,114,198,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,114,195,0,0, - 0,81,3,0,0,115,42,0,0,0,0,2,12,1,4,2, - 16,1,12,1,14,2,14,1,10,1,2,1,14,1,14,2, - 6,1,16,3,6,1,8,1,20,1,2,1,12,1,16,1, - 16,2,8,1,122,25,83,111,117,114,99,101,70,105,108,101, - 76,111,97,100,101,114,46,115,101,116,95,100,97,116,97,78, - 41,7,114,109,0,0,0,114,108,0,0,0,114,110,0,0, - 0,114,111,0,0,0,114,194,0,0,0,114,196,0,0,0, - 114,195,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,215,0,0,0,67,3, - 0,0,115,8,0,0,0,8,2,4,2,8,5,8,5,114, - 215,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, - 0,2,0,0,0,64,0,0,0,115,32,0,0,0,101,0, - 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0, - 90,4,100,4,100,5,132,0,90,5,100,6,83,0,41,7, - 218,20,83,111,117,114,99,101,108,101,115,115,70,105,108,101, - 76,111,97,100,101,114,122,45,76,111,97,100,101,114,32,119, - 104,105,99,104,32,104,97,110,100,108,101,115,32,115,111,117, - 114,99,101,108,101,115,115,32,102,105,108,101,32,105,109,112, - 111,114,116,115,46,99,2,0,0,0,0,0,0,0,5,0, - 0,0,5,0,0,0,67,0,0,0,115,48,0,0,0,124, - 0,106,0,124,1,131,1,125,2,124,0,106,1,124,2,131, - 1,125,3,116,2,124,3,124,1,124,2,100,1,141,3,125, - 4,116,3,124,4,124,1,124,2,100,2,141,3,83,0,41, - 3,78,41,2,114,102,0,0,0,114,37,0,0,0,41,2, - 114,102,0,0,0,114,93,0,0,0,41,4,114,155,0,0, - 0,114,197,0,0,0,114,139,0,0,0,114,145,0,0,0, - 41,5,114,104,0,0,0,114,123,0,0,0,114,37,0,0, - 0,114,56,0,0,0,114,206,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,116, - 3,0,0,115,8,0,0,0,0,1,10,1,10,1,14,1, - 122,29,83,111,117,114,99,101,108,101,115,115,70,105,108,101, - 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, - 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 39,82,101,116,117,114,110,32,78,111,110,101,32,97,115,32, - 116,104,101,114,101,32,105,115,32,110,111,32,115,111,117,114, - 99,101,32,99,111,100,101,46,78,114,4,0,0,0,41,2, - 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,199,0,0,0,122,3, - 0,0,115,2,0,0,0,0,2,122,31,83,111,117,114,99, - 101,108,101,115,115,70,105,108,101,76,111,97,100,101,114,46, - 103,101,116,95,115,111,117,114,99,101,78,41,6,114,109,0, - 0,0,114,108,0,0,0,114,110,0,0,0,114,111,0,0, - 0,114,184,0,0,0,114,199,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 220,0,0,0,112,3,0,0,115,6,0,0,0,8,2,4, - 2,8,6,114,220,0,0,0,99,0,0,0,0,0,0,0, - 0,0,0,0,0,3,0,0,0,64,0,0,0,115,92,0, - 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, - 100,3,132,0,90,4,100,4,100,5,132,0,90,5,100,6, - 100,7,132,0,90,6,100,8,100,9,132,0,90,7,100,10, - 100,11,132,0,90,8,100,12,100,13,132,0,90,9,100,14, - 100,15,132,0,90,10,100,16,100,17,132,0,90,11,101,12, - 100,18,100,19,132,0,131,1,90,13,100,20,83,0,41,21, - 218,19,69,120,116,101,110,115,105,111,110,70,105,108,101,76, - 111,97,100,101,114,122,93,76,111,97,100,101,114,32,102,111, - 114,32,101,120,116,101,110,115,105,111,110,32,109,111,100,117, - 108,101,115,46,10,10,32,32,32,32,84,104,101,32,99,111, - 110,115,116,114,117,99,116,111,114,32,105,115,32,100,101,115, - 105,103,110,101,100,32,116,111,32,119,111,114,107,32,119,105, - 116,104,32,70,105,108,101,70,105,110,100,101,114,46,10,10, - 32,32,32,32,99,3,0,0,0,0,0,0,0,3,0,0, - 0,2,0,0,0,67,0,0,0,115,16,0,0,0,124,1, - 124,0,95,0,124,2,124,0,95,1,100,0,83,0,41,1, - 78,41,2,114,102,0,0,0,114,37,0,0,0,41,3,114, - 104,0,0,0,114,102,0,0,0,114,37,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,182,0, - 0,0,139,3,0,0,115,4,0,0,0,0,1,6,1,122, - 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, - 97,100,101,114,46,95,95,105,110,105,116,95,95,99,2,0, - 0,0,0,0,0,0,2,0,0,0,2,0,0,0,67,0, - 0,0,115,24,0,0,0,124,0,106,0,124,1,106,0,107, - 2,111,22,124,0,106,1,124,1,106,1,107,2,83,0,41, - 1,78,41,2,114,208,0,0,0,114,115,0,0,0,41,2, - 114,104,0,0,0,114,209,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,210,0,0,0,143,3, - 0,0,115,4,0,0,0,0,1,12,1,122,26,69,120,116, + 0,114,4,0,0,0,114,6,0,0,0,114,184,0,0,0, + 170,3,0,0,115,2,0,0,0,0,2,122,28,69,120,116, 101,110,115,105,111,110,70,105,108,101,76,111,97,100,101,114, - 46,95,95,101,113,95,95,99,1,0,0,0,0,0,0,0, - 1,0,0,0,3,0,0,0,67,0,0,0,115,20,0,0, - 0,116,0,124,0,106,1,131,1,116,0,124,0,106,2,131, - 1,65,0,83,0,41,1,78,41,3,114,211,0,0,0,114, - 102,0,0,0,114,37,0,0,0,41,1,114,104,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 212,0,0,0,147,3,0,0,115,2,0,0,0,0,1,122, - 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, - 97,100,101,114,46,95,95,104,97,115,104,95,95,99,2,0, - 0,0,0,0,0,0,3,0,0,0,4,0,0,0,67,0, - 0,0,115,36,0,0,0,116,0,106,1,116,2,106,3,124, - 1,131,2,125,2,116,0,106,4,100,1,124,1,106,5,124, - 0,106,6,131,3,1,0,124,2,83,0,41,2,122,38,67, - 114,101,97,116,101,32,97,110,32,117,110,105,116,105,97,108, - 105,122,101,100,32,101,120,116,101,110,115,105,111,110,32,109, - 111,100,117,108,101,122,38,101,120,116,101,110,115,105,111,110, - 32,109,111,100,117,108,101,32,123,33,114,125,32,108,111,97, - 100,101,100,32,102,114,111,109,32,123,33,114,125,41,7,114, - 118,0,0,0,114,185,0,0,0,114,143,0,0,0,90,14, - 99,114,101,97,116,101,95,100,121,110,97,109,105,99,114,133, - 0,0,0,114,102,0,0,0,114,37,0,0,0,41,3,114, - 104,0,0,0,114,162,0,0,0,114,187,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,183,0, - 0,0,150,3,0,0,115,10,0,0,0,0,2,4,1,10, - 1,6,1,12,1,122,33,69,120,116,101,110,115,105,111,110, - 70,105,108,101,76,111,97,100,101,114,46,99,114,101,97,116, - 101,95,109,111,100,117,108,101,99,2,0,0,0,0,0,0, - 0,2,0,0,0,4,0,0,0,67,0,0,0,115,36,0, - 0,0,116,0,106,1,116,2,106,3,124,1,131,2,1,0, - 116,0,106,4,100,1,124,0,106,5,124,0,106,6,131,3, - 1,0,100,2,83,0,41,3,122,30,73,110,105,116,105,97, - 108,105,122,101,32,97,110,32,101,120,116,101,110,115,105,111, - 110,32,109,111,100,117,108,101,122,40,101,120,116,101,110,115, - 105,111,110,32,109,111,100,117,108,101,32,123,33,114,125,32, - 101,120,101,99,117,116,101,100,32,102,114,111,109,32,123,33, - 114,125,78,41,7,114,118,0,0,0,114,185,0,0,0,114, - 143,0,0,0,90,12,101,120,101,99,95,100,121,110,97,109, - 105,99,114,133,0,0,0,114,102,0,0,0,114,37,0,0, - 0,41,2,114,104,0,0,0,114,187,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,114,188,0,0, - 0,158,3,0,0,115,6,0,0,0,0,2,14,1,6,1, - 122,31,69,120,116,101,110,115,105,111,110,70,105,108,101,76, - 111,97,100,101,114,46,101,120,101,99,95,109,111,100,117,108, - 101,99,2,0,0,0,0,0,0,0,2,0,0,0,4,0, - 0,0,3,0,0,0,115,36,0,0,0,116,0,124,0,106, - 1,131,1,100,1,25,0,137,0,116,2,135,0,102,1,100, - 2,100,3,132,8,116,3,68,0,131,1,131,1,83,0,41, - 4,122,49,82,101,116,117,114,110,32,84,114,117,101,32,105, - 102,32,116,104,101,32,101,120,116,101,110,115,105,111,110,32, - 109,111,100,117,108,101,32,105,115,32,97,32,112,97,99,107, - 97,103,101,46,114,31,0,0,0,99,1,0,0,0,0,0, - 0,0,2,0,0,0,4,0,0,0,51,0,0,0,115,26, - 0,0,0,124,0,93,18,125,1,136,0,100,0,124,1,23, - 0,107,2,86,0,1,0,113,2,100,1,83,0,41,2,114, - 182,0,0,0,78,114,4,0,0,0,41,2,114,24,0,0, - 0,218,6,115,117,102,102,105,120,41,1,218,9,102,105,108, - 101,95,110,97,109,101,114,4,0,0,0,114,6,0,0,0, - 250,9,60,103,101,110,101,120,112,114,62,167,3,0,0,115, - 2,0,0,0,4,1,122,49,69,120,116,101,110,115,105,111, - 110,70,105,108,101,76,111,97,100,101,114,46,105,115,95,112, - 97,99,107,97,103,101,46,60,108,111,99,97,108,115,62,46, - 60,103,101,110,101,120,112,114,62,41,4,114,40,0,0,0, - 114,37,0,0,0,218,3,97,110,121,218,18,69,88,84,69, - 78,83,73,79,78,95,83,85,70,70,73,88,69,83,41,2, - 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,41, - 1,114,223,0,0,0,114,6,0,0,0,114,157,0,0,0, - 164,3,0,0,115,6,0,0,0,0,2,14,1,12,1,122, - 30,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, - 97,100,101,114,46,105,115,95,112,97,99,107,97,103,101,99, - 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 63,82,101,116,117,114,110,32,78,111,110,101,32,97,115,32, - 97,110,32,101,120,116,101,110,115,105,111,110,32,109,111,100, - 117,108,101,32,99,97,110,110,111,116,32,99,114,101,97,116, - 101,32,97,32,99,111,100,101,32,111,98,106,101,99,116,46, + 46,103,101,116,95,99,111,100,101,99,2,0,0,0,0,0, + 0,0,2,0,0,0,1,0,0,0,67,0,0,0,115,4, + 0,0,0,100,1,83,0,41,2,122,53,82,101,116,117,114, + 110,32,78,111,110,101,32,97,115,32,101,120,116,101,110,115, + 105,111,110,32,109,111,100,117,108,101,115,32,104,97,118,101, + 32,110,111,32,115,111,117,114,99,101,32,99,111,100,101,46, 78,114,4,0,0,0,41,2,114,104,0,0,0,114,123,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,184,0,0,0,170,3,0,0,115,2,0,0,0,0, - 2,122,28,69,120,116,101,110,115,105,111,110,70,105,108,101, - 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, - 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 53,82,101,116,117,114,110,32,78,111,110,101,32,97,115,32, - 101,120,116,101,110,115,105,111,110,32,109,111,100,117,108,101, - 115,32,104,97,118,101,32,110,111,32,115,111,117,114,99,101, - 32,99,111,100,101,46,78,114,4,0,0,0,41,2,114,104, - 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,199,0,0,0,174,3,0,0, - 115,2,0,0,0,0,2,122,30,69,120,116,101,110,115,105, - 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, - 95,115,111,117,114,99,101,99,2,0,0,0,0,0,0,0, - 2,0,0,0,1,0,0,0,67,0,0,0,115,6,0,0, - 0,124,0,106,0,83,0,41,1,122,58,82,101,116,117,114, - 110,32,116,104,101,32,112,97,116,104,32,116,111,32,116,104, - 101,32,115,111,117,114,99,101,32,102,105,108,101,32,97,115, - 32,102,111,117,110,100,32,98,121,32,116,104,101,32,102,105, - 110,100,101,114,46,41,1,114,37,0,0,0,41,2,114,104, - 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,155,0,0,0,178,3,0,0, - 115,2,0,0,0,0,3,122,32,69,120,116,101,110,115,105, - 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, - 95,102,105,108,101,110,97,109,101,78,41,14,114,109,0,0, + 0,114,199,0,0,0,174,3,0,0,115,2,0,0,0,0, + 2,122,30,69,120,116,101,110,115,105,111,110,70,105,108,101, + 76,111,97,100,101,114,46,103,101,116,95,115,111,117,114,99, + 101,99,2,0,0,0,0,0,0,0,2,0,0,0,1,0, + 0,0,67,0,0,0,115,6,0,0,0,124,0,106,0,83, + 0,41,1,122,58,82,101,116,117,114,110,32,116,104,101,32, + 112,97,116,104,32,116,111,32,116,104,101,32,115,111,117,114, + 99,101,32,102,105,108,101,32,97,115,32,102,111,117,110,100, + 32,98,121,32,116,104,101,32,102,105,110,100,101,114,46,41, + 1,114,37,0,0,0,41,2,114,104,0,0,0,114,123,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,114,155,0,0,0,178,3,0,0,115,2,0,0,0,0, + 3,122,32,69,120,116,101,110,115,105,111,110,70,105,108,101, + 76,111,97,100,101,114,46,103,101,116,95,102,105,108,101,110, + 97,109,101,78,41,14,114,109,0,0,0,114,108,0,0,0, + 114,110,0,0,0,114,111,0,0,0,114,182,0,0,0,114, + 210,0,0,0,114,212,0,0,0,114,183,0,0,0,114,188, + 0,0,0,114,157,0,0,0,114,184,0,0,0,114,199,0, + 0,0,114,120,0,0,0,114,155,0,0,0,114,4,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 114,221,0,0,0,131,3,0,0,115,20,0,0,0,8,6, + 4,2,8,4,8,4,8,3,8,8,8,6,8,6,8,4, + 8,4,114,221,0,0,0,99,0,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0,64,0,0,0,115,96,0,0, + 0,101,0,90,1,100,0,90,2,100,1,90,3,100,2,100, + 3,132,0,90,4,100,4,100,5,132,0,90,5,100,6,100, + 7,132,0,90,6,100,8,100,9,132,0,90,7,100,10,100, + 11,132,0,90,8,100,12,100,13,132,0,90,9,100,14,100, + 15,132,0,90,10,100,16,100,17,132,0,90,11,100,18,100, + 19,132,0,90,12,100,20,100,21,132,0,90,13,100,22,83, + 0,41,23,218,14,95,78,97,109,101,115,112,97,99,101,80, + 97,116,104,97,38,1,0,0,82,101,112,114,101,115,101,110, + 116,115,32,97,32,110,97,109,101,115,112,97,99,101,32,112, + 97,99,107,97,103,101,39,115,32,112,97,116,104,46,32,32, + 73,116,32,117,115,101,115,32,116,104,101,32,109,111,100,117, + 108,101,32,110,97,109,101,10,32,32,32,32,116,111,32,102, + 105,110,100,32,105,116,115,32,112,97,114,101,110,116,32,109, + 111,100,117,108,101,44,32,97,110,100,32,102,114,111,109,32, + 116,104,101,114,101,32,105,116,32,108,111,111,107,115,32,117, + 112,32,116,104,101,32,112,97,114,101,110,116,39,115,10,32, + 32,32,32,95,95,112,97,116,104,95,95,46,32,32,87,104, + 101,110,32,116,104,105,115,32,99,104,97,110,103,101,115,44, + 32,116,104,101,32,109,111,100,117,108,101,39,115,32,111,119, + 110,32,112,97,116,104,32,105,115,32,114,101,99,111,109,112, + 117,116,101,100,44,10,32,32,32,32,117,115,105,110,103,32, + 112,97,116,104,95,102,105,110,100,101,114,46,32,32,70,111, + 114,32,116,111,112,45,108,101,118,101,108,32,109,111,100,117, + 108,101,115,44,32,116,104,101,32,112,97,114,101,110,116,32, + 109,111,100,117,108,101,39,115,32,112,97,116,104,10,32,32, + 32,32,105,115,32,115,121,115,46,112,97,116,104,46,99,4, + 0,0,0,0,0,0,0,4,0,0,0,2,0,0,0,67, + 0,0,0,115,36,0,0,0,124,1,124,0,95,0,124,2, + 124,0,95,1,116,2,124,0,106,3,131,0,131,1,124,0, + 95,4,124,3,124,0,95,5,100,0,83,0,41,1,78,41, + 6,218,5,95,110,97,109,101,218,5,95,112,97,116,104,114, + 97,0,0,0,218,16,95,103,101,116,95,112,97,114,101,110, + 116,95,112,97,116,104,218,17,95,108,97,115,116,95,112,97, + 114,101,110,116,95,112,97,116,104,218,12,95,112,97,116,104, + 95,102,105,110,100,101,114,41,4,114,104,0,0,0,114,102, + 0,0,0,114,37,0,0,0,218,11,112,97,116,104,95,102, + 105,110,100,101,114,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,114,182,0,0,0,191,3,0,0,115,8,0, + 0,0,0,1,6,1,6,1,14,1,122,23,95,78,97,109, + 101,115,112,97,99,101,80,97,116,104,46,95,95,105,110,105, + 116,95,95,99,1,0,0,0,0,0,0,0,4,0,0,0, + 3,0,0,0,67,0,0,0,115,38,0,0,0,124,0,106, + 0,106,1,100,1,131,1,92,3,125,1,125,2,125,3,124, + 2,100,2,107,2,114,30,100,6,83,0,124,1,100,5,102, + 2,83,0,41,7,122,62,82,101,116,117,114,110,115,32,97, + 32,116,117,112,108,101,32,111,102,32,40,112,97,114,101,110, + 116,45,109,111,100,117,108,101,45,110,97,109,101,44,32,112, + 97,114,101,110,116,45,112,97,116,104,45,97,116,116,114,45, + 110,97,109,101,41,114,61,0,0,0,114,32,0,0,0,114, + 8,0,0,0,114,37,0,0,0,90,8,95,95,112,97,116, + 104,95,95,41,2,114,8,0,0,0,114,37,0,0,0,41, + 2,114,228,0,0,0,114,34,0,0,0,41,4,114,104,0, + 0,0,114,219,0,0,0,218,3,100,111,116,90,2,109,101, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, + 23,95,102,105,110,100,95,112,97,114,101,110,116,95,112,97, + 116,104,95,110,97,109,101,115,197,3,0,0,115,8,0,0, + 0,0,2,18,1,8,2,4,3,122,38,95,78,97,109,101, + 115,112,97,99,101,80,97,116,104,46,95,102,105,110,100,95, + 112,97,114,101,110,116,95,112,97,116,104,95,110,97,109,101, + 115,99,1,0,0,0,0,0,0,0,3,0,0,0,3,0, + 0,0,67,0,0,0,115,28,0,0,0,124,0,106,0,131, + 0,92,2,125,1,125,2,116,1,116,2,106,3,124,1,25, + 0,124,2,131,2,83,0,41,1,78,41,4,114,235,0,0, + 0,114,114,0,0,0,114,8,0,0,0,218,7,109,111,100, + 117,108,101,115,41,3,114,104,0,0,0,90,18,112,97,114, + 101,110,116,95,109,111,100,117,108,101,95,110,97,109,101,90, + 14,112,97,116,104,95,97,116,116,114,95,110,97,109,101,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,114,230, + 0,0,0,207,3,0,0,115,4,0,0,0,0,1,12,1, + 122,31,95,78,97,109,101,115,112,97,99,101,80,97,116,104, + 46,95,103,101,116,95,112,97,114,101,110,116,95,112,97,116, + 104,99,1,0,0,0,0,0,0,0,3,0,0,0,3,0, + 0,0,67,0,0,0,115,80,0,0,0,116,0,124,0,106, + 1,131,0,131,1,125,1,124,1,124,0,106,2,107,3,114, + 74,124,0,106,3,124,0,106,4,124,1,131,2,125,2,124, + 2,100,0,107,9,114,68,124,2,106,5,100,0,107,8,114, + 68,124,2,106,6,114,68,124,2,106,6,124,0,95,7,124, + 1,124,0,95,2,124,0,106,7,83,0,41,1,78,41,8, + 114,97,0,0,0,114,230,0,0,0,114,231,0,0,0,114, + 232,0,0,0,114,228,0,0,0,114,124,0,0,0,114,154, + 0,0,0,114,229,0,0,0,41,3,114,104,0,0,0,90, + 11,112,97,114,101,110,116,95,112,97,116,104,114,162,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,12,95,114,101,99,97,108,99,117,108,97,116,101,211,3, + 0,0,115,16,0,0,0,0,2,12,1,10,1,14,3,18, + 1,6,1,8,1,6,1,122,27,95,78,97,109,101,115,112, + 97,99,101,80,97,116,104,46,95,114,101,99,97,108,99,117, + 108,97,116,101,99,1,0,0,0,0,0,0,0,1,0,0, + 0,2,0,0,0,67,0,0,0,115,12,0,0,0,116,0, + 124,0,106,1,131,0,131,1,83,0,41,1,78,41,2,218, + 4,105,116,101,114,114,237,0,0,0,41,1,114,104,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,8,95,95,105,116,101,114,95,95,224,3,0,0,115,2, + 0,0,0,0,1,122,23,95,78,97,109,101,115,112,97,99, + 101,80,97,116,104,46,95,95,105,116,101,114,95,95,99,3, + 0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,67, + 0,0,0,115,14,0,0,0,124,2,124,0,106,0,124,1, + 60,0,100,0,83,0,41,1,78,41,1,114,229,0,0,0, + 41,3,114,104,0,0,0,218,5,105,110,100,101,120,114,37, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,218,11,95,95,115,101,116,105,116,101,109,95,95,227, + 3,0,0,115,2,0,0,0,0,1,122,26,95,78,97,109, + 101,115,112,97,99,101,80,97,116,104,46,95,95,115,101,116, + 105,116,101,109,95,95,99,1,0,0,0,0,0,0,0,1, + 0,0,0,2,0,0,0,67,0,0,0,115,12,0,0,0, + 116,0,124,0,106,1,131,0,131,1,83,0,41,1,78,41, + 2,114,33,0,0,0,114,237,0,0,0,41,1,114,104,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,218,7,95,95,108,101,110,95,95,230,3,0,0,115,2, + 0,0,0,0,1,122,22,95,78,97,109,101,115,112,97,99, + 101,80,97,116,104,46,95,95,108,101,110,95,95,99,1,0, + 0,0,0,0,0,0,1,0,0,0,2,0,0,0,67,0, + 0,0,115,12,0,0,0,100,1,106,0,124,0,106,1,131, + 1,83,0,41,2,78,122,20,95,78,97,109,101,115,112,97, + 99,101,80,97,116,104,40,123,33,114,125,41,41,2,114,50, + 0,0,0,114,229,0,0,0,41,1,114,104,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,8, + 95,95,114,101,112,114,95,95,233,3,0,0,115,2,0,0, + 0,0,1,122,23,95,78,97,109,101,115,112,97,99,101,80, + 97,116,104,46,95,95,114,101,112,114,95,95,99,2,0,0, + 0,0,0,0,0,2,0,0,0,2,0,0,0,67,0,0, + 0,115,12,0,0,0,124,1,124,0,106,0,131,0,107,6, + 83,0,41,1,78,41,1,114,237,0,0,0,41,2,114,104, + 0,0,0,218,4,105,116,101,109,114,4,0,0,0,114,4, + 0,0,0,114,6,0,0,0,218,12,95,95,99,111,110,116, + 97,105,110,115,95,95,236,3,0,0,115,2,0,0,0,0, + 1,122,27,95,78,97,109,101,115,112,97,99,101,80,97,116, + 104,46,95,95,99,111,110,116,97,105,110,115,95,95,99,2, + 0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,67, + 0,0,0,115,16,0,0,0,124,0,106,0,106,1,124,1, + 131,1,1,0,100,0,83,0,41,1,78,41,2,114,229,0, + 0,0,114,161,0,0,0,41,2,114,104,0,0,0,114,244, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,161,0,0,0,239,3,0,0,115,2,0,0,0, + 0,1,122,21,95,78,97,109,101,115,112,97,99,101,80,97, + 116,104,46,97,112,112,101,110,100,78,41,14,114,109,0,0, 0,114,108,0,0,0,114,110,0,0,0,114,111,0,0,0, - 114,182,0,0,0,114,210,0,0,0,114,212,0,0,0,114, - 183,0,0,0,114,188,0,0,0,114,157,0,0,0,114,184, - 0,0,0,114,199,0,0,0,114,120,0,0,0,114,155,0, + 114,182,0,0,0,114,235,0,0,0,114,230,0,0,0,114, + 237,0,0,0,114,239,0,0,0,114,241,0,0,0,114,242, + 0,0,0,114,243,0,0,0,114,245,0,0,0,114,161,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,114,221,0,0,0,131,3,0,0,115, - 20,0,0,0,8,6,4,2,8,4,8,4,8,3,8,8, - 8,6,8,6,8,4,8,4,114,221,0,0,0,99,0,0, - 0,0,0,0,0,0,0,0,0,0,2,0,0,0,64,0, - 0,0,115,96,0,0,0,101,0,90,1,100,0,90,2,100, - 1,90,3,100,2,100,3,132,0,90,4,100,4,100,5,132, - 0,90,5,100,6,100,7,132,0,90,6,100,8,100,9,132, - 0,90,7,100,10,100,11,132,0,90,8,100,12,100,13,132, - 0,90,9,100,14,100,15,132,0,90,10,100,16,100,17,132, - 0,90,11,100,18,100,19,132,0,90,12,100,20,100,21,132, - 0,90,13,100,22,83,0,41,23,218,14,95,78,97,109,101, - 115,112,97,99,101,80,97,116,104,97,38,1,0,0,82,101, - 112,114,101,115,101,110,116,115,32,97,32,110,97,109,101,115, - 112,97,99,101,32,112,97,99,107,97,103,101,39,115,32,112, - 97,116,104,46,32,32,73,116,32,117,115,101,115,32,116,104, - 101,32,109,111,100,117,108,101,32,110,97,109,101,10,32,32, - 32,32,116,111,32,102,105,110,100,32,105,116,115,32,112,97, - 114,101,110,116,32,109,111,100,117,108,101,44,32,97,110,100, - 32,102,114,111,109,32,116,104,101,114,101,32,105,116,32,108, - 111,111,107,115,32,117,112,32,116,104,101,32,112,97,114,101, - 110,116,39,115,10,32,32,32,32,95,95,112,97,116,104,95, - 95,46,32,32,87,104,101,110,32,116,104,105,115,32,99,104, - 97,110,103,101,115,44,32,116,104,101,32,109,111,100,117,108, - 101,39,115,32,111,119,110,32,112,97,116,104,32,105,115,32, - 114,101,99,111,109,112,117,116,101,100,44,10,32,32,32,32, - 117,115,105,110,103,32,112,97,116,104,95,102,105,110,100,101, - 114,46,32,32,70,111,114,32,116,111,112,45,108,101,118,101, - 108,32,109,111,100,117,108,101,115,44,32,116,104,101,32,112, - 97,114,101,110,116,32,109,111,100,117,108,101,39,115,32,112, - 97,116,104,10,32,32,32,32,105,115,32,115,121,115,46,112, - 97,116,104,46,99,4,0,0,0,0,0,0,0,4,0,0, - 0,2,0,0,0,67,0,0,0,115,36,0,0,0,124,1, - 124,0,95,0,124,2,124,0,95,1,116,2,124,0,106,3, - 131,0,131,1,124,0,95,4,124,3,124,0,95,5,100,0, - 83,0,41,1,78,41,6,218,5,95,110,97,109,101,218,5, - 95,112,97,116,104,114,97,0,0,0,218,16,95,103,101,116, - 95,112,97,114,101,110,116,95,112,97,116,104,218,17,95,108, - 97,115,116,95,112,97,114,101,110,116,95,112,97,116,104,218, - 12,95,112,97,116,104,95,102,105,110,100,101,114,41,4,114, - 104,0,0,0,114,102,0,0,0,114,37,0,0,0,218,11, - 112,97,116,104,95,102,105,110,100,101,114,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,182,0,0,0,191, - 3,0,0,115,8,0,0,0,0,1,6,1,6,1,14,1, - 122,23,95,78,97,109,101,115,112,97,99,101,80,97,116,104, - 46,95,95,105,110,105,116,95,95,99,1,0,0,0,0,0, - 0,0,4,0,0,0,3,0,0,0,67,0,0,0,115,38, - 0,0,0,124,0,106,0,106,1,100,1,131,1,92,3,125, - 1,125,2,125,3,124,2,100,2,107,2,114,30,100,6,83, - 0,124,1,100,5,102,2,83,0,41,7,122,62,82,101,116, - 117,114,110,115,32,97,32,116,117,112,108,101,32,111,102,32, - 40,112,97,114,101,110,116,45,109,111,100,117,108,101,45,110, - 97,109,101,44,32,112,97,114,101,110,116,45,112,97,116,104, - 45,97,116,116,114,45,110,97,109,101,41,114,61,0,0,0, - 114,32,0,0,0,114,8,0,0,0,114,37,0,0,0,90, - 8,95,95,112,97,116,104,95,95,41,2,114,8,0,0,0, - 114,37,0,0,0,41,2,114,228,0,0,0,114,34,0,0, - 0,41,4,114,104,0,0,0,114,219,0,0,0,218,3,100, - 111,116,90,2,109,101,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,218,23,95,102,105,110,100,95,112,97,114, - 101,110,116,95,112,97,116,104,95,110,97,109,101,115,197,3, - 0,0,115,8,0,0,0,0,2,18,1,8,2,4,3,122, - 38,95,78,97,109,101,115,112,97,99,101,80,97,116,104,46, - 95,102,105,110,100,95,112,97,114,101,110,116,95,112,97,116, - 104,95,110,97,109,101,115,99,1,0,0,0,0,0,0,0, - 3,0,0,0,3,0,0,0,67,0,0,0,115,28,0,0, - 0,124,0,106,0,131,0,92,2,125,1,125,2,116,1,116, - 2,106,3,124,1,25,0,124,2,131,2,83,0,41,1,78, - 41,4,114,235,0,0,0,114,114,0,0,0,114,8,0,0, - 0,218,7,109,111,100,117,108,101,115,41,3,114,104,0,0, - 0,90,18,112,97,114,101,110,116,95,109,111,100,117,108,101, - 95,110,97,109,101,90,14,112,97,116,104,95,97,116,116,114, - 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,230,0,0,0,207,3,0,0,115,4,0, - 0,0,0,1,12,1,122,31,95,78,97,109,101,115,112,97, - 99,101,80,97,116,104,46,95,103,101,116,95,112,97,114,101, - 110,116,95,112,97,116,104,99,1,0,0,0,0,0,0,0, - 3,0,0,0,3,0,0,0,67,0,0,0,115,80,0,0, - 0,116,0,124,0,106,1,131,0,131,1,125,1,124,1,124, - 0,106,2,107,3,114,74,124,0,106,3,124,0,106,4,124, - 1,131,2,125,2,124,2,100,0,107,9,114,68,124,2,106, - 5,100,0,107,8,114,68,124,2,106,6,114,68,124,2,106, - 6,124,0,95,7,124,1,124,0,95,2,124,0,106,7,83, - 0,41,1,78,41,8,114,97,0,0,0,114,230,0,0,0, - 114,231,0,0,0,114,232,0,0,0,114,228,0,0,0,114, - 124,0,0,0,114,154,0,0,0,114,229,0,0,0,41,3, - 114,104,0,0,0,90,11,112,97,114,101,110,116,95,112,97, - 116,104,114,162,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,12,95,114,101,99,97,108,99,117, - 108,97,116,101,211,3,0,0,115,16,0,0,0,0,2,12, - 1,10,1,14,3,18,1,6,1,8,1,6,1,122,27,95, - 78,97,109,101,115,112,97,99,101,80,97,116,104,46,95,114, - 101,99,97,108,99,117,108,97,116,101,99,1,0,0,0,0, - 0,0,0,1,0,0,0,2,0,0,0,67,0,0,0,115, - 12,0,0,0,116,0,124,0,106,1,131,0,131,1,83,0, - 41,1,78,41,2,218,4,105,116,101,114,114,237,0,0,0, - 41,1,114,104,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,8,95,95,105,116,101,114,95,95, - 224,3,0,0,115,2,0,0,0,0,1,122,23,95,78,97, - 109,101,115,112,97,99,101,80,97,116,104,46,95,95,105,116, - 101,114,95,95,99,3,0,0,0,0,0,0,0,3,0,0, - 0,3,0,0,0,67,0,0,0,115,14,0,0,0,124,2, - 124,0,106,0,124,1,60,0,100,0,83,0,41,1,78,41, - 1,114,229,0,0,0,41,3,114,104,0,0,0,218,5,105, - 110,100,101,120,114,37,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,218,11,95,95,115,101,116,105, - 116,101,109,95,95,227,3,0,0,115,2,0,0,0,0,1, - 122,26,95,78,97,109,101,115,112,97,99,101,80,97,116,104, - 46,95,95,115,101,116,105,116,101,109,95,95,99,1,0,0, - 0,0,0,0,0,1,0,0,0,2,0,0,0,67,0,0, - 0,115,12,0,0,0,116,0,124,0,106,1,131,0,131,1, - 83,0,41,1,78,41,2,114,33,0,0,0,114,237,0,0, - 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,218,7,95,95,108,101,110,95,95, - 230,3,0,0,115,2,0,0,0,0,1,122,22,95,78,97, - 109,101,115,112,97,99,101,80,97,116,104,46,95,95,108,101, - 110,95,95,99,1,0,0,0,0,0,0,0,1,0,0,0, - 2,0,0,0,67,0,0,0,115,12,0,0,0,100,1,106, - 0,124,0,106,1,131,1,83,0,41,2,78,122,20,95,78, - 97,109,101,115,112,97,99,101,80,97,116,104,40,123,33,114, - 125,41,41,2,114,50,0,0,0,114,229,0,0,0,41,1, - 114,104,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,8,95,95,114,101,112,114,95,95,233,3, - 0,0,115,2,0,0,0,0,1,122,23,95,78,97,109,101, - 115,112,97,99,101,80,97,116,104,46,95,95,114,101,112,114, - 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, - 0,0,0,67,0,0,0,115,12,0,0,0,124,1,124,0, - 106,0,131,0,107,6,83,0,41,1,78,41,1,114,237,0, - 0,0,41,2,114,104,0,0,0,218,4,105,116,101,109,114, - 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,12, - 95,95,99,111,110,116,97,105,110,115,95,95,236,3,0,0, - 115,2,0,0,0,0,1,122,27,95,78,97,109,101,115,112, - 97,99,101,80,97,116,104,46,95,95,99,111,110,116,97,105, - 110,115,95,95,99,2,0,0,0,0,0,0,0,2,0,0, - 0,2,0,0,0,67,0,0,0,115,16,0,0,0,124,0, - 106,0,106,1,124,1,131,1,1,0,100,0,83,0,41,1, - 78,41,2,114,229,0,0,0,114,161,0,0,0,41,2,114, - 104,0,0,0,114,244,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,161,0,0,0,239,3,0, - 0,115,2,0,0,0,0,1,122,21,95,78,97,109,101,115, - 112,97,99,101,80,97,116,104,46,97,112,112,101,110,100,78, - 41,14,114,109,0,0,0,114,108,0,0,0,114,110,0,0, - 0,114,111,0,0,0,114,182,0,0,0,114,235,0,0,0, - 114,230,0,0,0,114,237,0,0,0,114,239,0,0,0,114, - 241,0,0,0,114,242,0,0,0,114,243,0,0,0,114,245, - 0,0,0,114,161,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,114,227,0,0, - 0,184,3,0,0,115,22,0,0,0,8,5,4,2,8,6, - 8,10,8,4,8,13,8,3,8,3,8,3,8,3,8,3, - 114,227,0,0,0,99,0,0,0,0,0,0,0,0,0,0, - 0,0,3,0,0,0,64,0,0,0,115,80,0,0,0,101, - 0,90,1,100,0,90,2,100,1,100,2,132,0,90,3,101, - 4,100,3,100,4,132,0,131,1,90,5,100,5,100,6,132, - 0,90,6,100,7,100,8,132,0,90,7,100,9,100,10,132, - 0,90,8,100,11,100,12,132,0,90,9,100,13,100,14,132, - 0,90,10,100,15,100,16,132,0,90,11,100,17,83,0,41, - 18,218,16,95,78,97,109,101,115,112,97,99,101,76,111,97, - 100,101,114,99,4,0,0,0,0,0,0,0,4,0,0,0, - 4,0,0,0,67,0,0,0,115,18,0,0,0,116,0,124, - 1,124,2,124,3,131,3,124,0,95,1,100,0,83,0,41, - 1,78,41,2,114,227,0,0,0,114,229,0,0,0,41,4, - 114,104,0,0,0,114,102,0,0,0,114,37,0,0,0,114, - 233,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,182,0,0,0,245,3,0,0,115,2,0,0, - 0,0,1,122,25,95,78,97,109,101,115,112,97,99,101,76, - 111,97,100,101,114,46,95,95,105,110,105,116,95,95,99,2, - 0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,67, - 0,0,0,115,12,0,0,0,100,1,106,0,124,1,106,1, - 131,1,83,0,41,2,122,115,82,101,116,117,114,110,32,114, - 101,112,114,32,102,111,114,32,116,104,101,32,109,111,100,117, - 108,101,46,10,10,32,32,32,32,32,32,32,32,84,104,101, - 32,109,101,116,104,111,100,32,105,115,32,100,101,112,114,101, - 99,97,116,101,100,46,32,32,84,104,101,32,105,109,112,111, - 114,116,32,109,97,99,104,105,110,101,114,121,32,100,111,101, - 115,32,116,104,101,32,106,111,98,32,105,116,115,101,108,102, - 46,10,10,32,32,32,32,32,32,32,32,122,25,60,109,111, - 100,117,108,101,32,123,33,114,125,32,40,110,97,109,101,115, - 112,97,99,101,41,62,41,2,114,50,0,0,0,114,109,0, - 0,0,41,2,114,168,0,0,0,114,187,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,109, - 111,100,117,108,101,95,114,101,112,114,248,3,0,0,115,2, - 0,0,0,0,7,122,28,95,78,97,109,101,115,112,97,99, - 101,76,111,97,100,101,114,46,109,111,100,117,108,101,95,114, - 101,112,114,99,2,0,0,0,0,0,0,0,2,0,0,0, - 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, - 0,41,2,78,84,114,4,0,0,0,41,2,114,104,0,0, - 0,114,123,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,114,157,0,0,0,1,4,0,0,115,2, - 0,0,0,0,1,122,27,95,78,97,109,101,115,112,97,99, - 101,76,111,97,100,101,114,46,105,115,95,112,97,99,107,97, - 103,101,99,2,0,0,0,0,0,0,0,2,0,0,0,1, - 0,0,0,67,0,0,0,115,4,0,0,0,100,1,83,0, - 41,2,78,114,32,0,0,0,114,4,0,0,0,41,2,114, - 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,199,0,0,0,4,4,0, - 0,115,2,0,0,0,0,1,122,27,95,78,97,109,101,115, - 112,97,99,101,76,111,97,100,101,114,46,103,101,116,95,115, - 111,117,114,99,101,99,2,0,0,0,0,0,0,0,2,0, - 0,0,6,0,0,0,67,0,0,0,115,16,0,0,0,116, - 0,100,1,100,2,100,3,100,4,100,5,141,4,83,0,41, - 6,78,114,32,0,0,0,122,8,60,115,116,114,105,110,103, - 62,114,186,0,0,0,84,41,1,114,201,0,0,0,41,1, - 114,202,0,0,0,41,2,114,104,0,0,0,114,123,0,0, + 0,114,6,0,0,0,114,227,0,0,0,184,3,0,0,115, + 22,0,0,0,8,5,4,2,8,6,8,10,8,4,8,13, + 8,3,8,3,8,3,8,3,8,3,114,227,0,0,0,99, + 0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0, + 64,0,0,0,115,80,0,0,0,101,0,90,1,100,0,90, + 2,100,1,100,2,132,0,90,3,101,4,100,3,100,4,132, + 0,131,1,90,5,100,5,100,6,132,0,90,6,100,7,100, + 8,132,0,90,7,100,9,100,10,132,0,90,8,100,11,100, + 12,132,0,90,9,100,13,100,14,132,0,90,10,100,15,100, + 16,132,0,90,11,100,17,83,0,41,18,218,16,95,78,97, + 109,101,115,112,97,99,101,76,111,97,100,101,114,99,4,0, + 0,0,0,0,0,0,4,0,0,0,4,0,0,0,67,0, + 0,0,115,18,0,0,0,116,0,124,1,124,2,124,3,131, + 3,124,0,95,1,100,0,83,0,41,1,78,41,2,114,227, + 0,0,0,114,229,0,0,0,41,4,114,104,0,0,0,114, + 102,0,0,0,114,37,0,0,0,114,233,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,182,0, + 0,0,245,3,0,0,115,2,0,0,0,0,1,122,25,95, + 78,97,109,101,115,112,97,99,101,76,111,97,100,101,114,46, + 95,95,105,110,105,116,95,95,99,2,0,0,0,0,0,0, + 0,2,0,0,0,2,0,0,0,67,0,0,0,115,12,0, + 0,0,100,1,106,0,124,1,106,1,131,1,83,0,41,2, + 122,115,82,101,116,117,114,110,32,114,101,112,114,32,102,111, + 114,32,116,104,101,32,109,111,100,117,108,101,46,10,10,32, + 32,32,32,32,32,32,32,84,104,101,32,109,101,116,104,111, + 100,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46, + 32,32,84,104,101,32,105,109,112,111,114,116,32,109,97,99, + 104,105,110,101,114,121,32,100,111,101,115,32,116,104,101,32, + 106,111,98,32,105,116,115,101,108,102,46,10,10,32,32,32, + 32,32,32,32,32,122,25,60,109,111,100,117,108,101,32,123, + 33,114,125,32,40,110,97,109,101,115,112,97,99,101,41,62, + 41,2,114,50,0,0,0,114,109,0,0,0,41,2,114,168, + 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,11,109,111,100,117,108,101,95, + 114,101,112,114,248,3,0,0,115,2,0,0,0,0,7,122, + 28,95,78,97,109,101,115,112,97,99,101,76,111,97,100,101, + 114,46,109,111,100,117,108,101,95,114,101,112,114,99,2,0, + 0,0,0,0,0,0,2,0,0,0,1,0,0,0,67,0, + 0,0,115,4,0,0,0,100,1,83,0,41,2,78,84,114, + 4,0,0,0,41,2,114,104,0,0,0,114,123,0,0,0, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, + 157,0,0,0,1,4,0,0,115,2,0,0,0,0,1,122, + 27,95,78,97,109,101,115,112,97,99,101,76,111,97,100,101, + 114,46,105,115,95,112,97,99,107,97,103,101,99,2,0,0, + 0,0,0,0,0,2,0,0,0,1,0,0,0,67,0,0, + 0,115,4,0,0,0,100,1,83,0,41,2,78,114,32,0, + 0,0,114,4,0,0,0,41,2,114,104,0,0,0,114,123, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,199,0,0,0,4,4,0,0,115,2,0,0,0, + 0,1,122,27,95,78,97,109,101,115,112,97,99,101,76,111, + 97,100,101,114,46,103,101,116,95,115,111,117,114,99,101,99, + 2,0,0,0,0,0,0,0,2,0,0,0,6,0,0,0, + 67,0,0,0,115,16,0,0,0,116,0,100,1,100,2,100, + 3,100,4,100,5,141,4,83,0,41,6,78,114,32,0,0, + 0,122,8,60,115,116,114,105,110,103,62,114,186,0,0,0, + 84,41,1,114,201,0,0,0,41,1,114,202,0,0,0,41, + 2,114,104,0,0,0,114,123,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,7, + 4,0,0,115,2,0,0,0,0,1,122,25,95,78,97,109, + 101,115,112,97,99,101,76,111,97,100,101,114,46,103,101,116, + 95,99,111,100,101,99,2,0,0,0,0,0,0,0,2,0, + 0,0,1,0,0,0,67,0,0,0,115,4,0,0,0,100, + 1,83,0,41,2,122,42,85,115,101,32,100,101,102,97,117, + 108,116,32,115,101,109,97,110,116,105,99,115,32,102,111,114, + 32,109,111,100,117,108,101,32,99,114,101,97,116,105,111,110, + 46,78,114,4,0,0,0,41,2,114,104,0,0,0,114,162, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,183,0,0,0,10,4,0,0,115,0,0,0,0, + 122,30,95,78,97,109,101,115,112,97,99,101,76,111,97,100, + 101,114,46,99,114,101,97,116,101,95,109,111,100,117,108,101, + 99,2,0,0,0,0,0,0,0,2,0,0,0,1,0,0, + 0,67,0,0,0,115,4,0,0,0,100,0,83,0,41,1, + 78,114,4,0,0,0,41,2,114,104,0,0,0,114,187,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,114,188,0,0,0,13,4,0,0,115,2,0,0,0,0, + 1,122,28,95,78,97,109,101,115,112,97,99,101,76,111,97, + 100,101,114,46,101,120,101,99,95,109,111,100,117,108,101,99, + 2,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0, + 67,0,0,0,115,26,0,0,0,116,0,106,1,100,1,124, + 0,106,2,131,2,1,0,116,0,106,3,124,0,124,1,131, + 2,83,0,41,2,122,98,76,111,97,100,32,97,32,110,97, + 109,101,115,112,97,99,101,32,109,111,100,117,108,101,46,10, + 10,32,32,32,32,32,32,32,32,84,104,105,115,32,109,101, + 116,104,111,100,32,105,115,32,100,101,112,114,101,99,97,116, + 101,100,46,32,32,85,115,101,32,101,120,101,99,95,109,111, + 100,117,108,101,40,41,32,105,110,115,116,101,97,100,46,10, + 10,32,32,32,32,32,32,32,32,122,38,110,97,109,101,115, + 112,97,99,101,32,109,111,100,117,108,101,32,108,111,97,100, + 101,100,32,119,105,116,104,32,112,97,116,104,32,123,33,114, + 125,41,4,114,118,0,0,0,114,133,0,0,0,114,229,0, + 0,0,114,189,0,0,0,41,2,114,104,0,0,0,114,123, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,190,0,0,0,16,4,0,0,115,6,0,0,0, + 0,7,6,1,8,1,122,28,95,78,97,109,101,115,112,97, + 99,101,76,111,97,100,101,114,46,108,111,97,100,95,109,111, + 100,117,108,101,78,41,12,114,109,0,0,0,114,108,0,0, + 0,114,110,0,0,0,114,182,0,0,0,114,180,0,0,0, + 114,247,0,0,0,114,157,0,0,0,114,199,0,0,0,114, + 184,0,0,0,114,183,0,0,0,114,188,0,0,0,114,190, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,246,0,0,0,244,3,0,0, + 115,16,0,0,0,8,1,8,3,12,9,8,3,8,3,8, + 3,8,3,8,3,114,246,0,0,0,99,0,0,0,0,0, + 0,0,0,0,0,0,0,4,0,0,0,64,0,0,0,115, + 106,0,0,0,101,0,90,1,100,0,90,2,100,1,90,3, + 101,4,100,2,100,3,132,0,131,1,90,5,101,4,100,4, + 100,5,132,0,131,1,90,6,101,4,100,6,100,7,132,0, + 131,1,90,7,101,4,100,8,100,9,132,0,131,1,90,8, + 101,4,100,17,100,11,100,12,132,1,131,1,90,9,101,4, + 100,18,100,13,100,14,132,1,131,1,90,10,101,4,100,19, + 100,15,100,16,132,1,131,1,90,11,100,10,83,0,41,20, + 218,10,80,97,116,104,70,105,110,100,101,114,122,62,77,101, + 116,97,32,112,97,116,104,32,102,105,110,100,101,114,32,102, + 111,114,32,115,121,115,46,112,97,116,104,32,97,110,100,32, + 112,97,99,107,97,103,101,32,95,95,112,97,116,104,95,95, + 32,97,116,116,114,105,98,117,116,101,115,46,99,1,0,0, + 0,0,0,0,0,2,0,0,0,4,0,0,0,67,0,0, + 0,115,42,0,0,0,120,36,116,0,106,1,106,2,131,0, + 68,0,93,22,125,1,116,3,124,1,100,1,131,2,114,12, + 124,1,106,4,131,0,1,0,113,12,87,0,100,2,83,0, + 41,3,122,125,67,97,108,108,32,116,104,101,32,105,110,118, + 97,108,105,100,97,116,101,95,99,97,99,104,101,115,40,41, + 32,109,101,116,104,111,100,32,111,110,32,97,108,108,32,112, + 97,116,104,32,101,110,116,114,121,32,102,105,110,100,101,114, + 115,10,32,32,32,32,32,32,32,32,115,116,111,114,101,100, + 32,105,110,32,115,121,115,46,112,97,116,104,95,105,109,112, + 111,114,116,101,114,95,99,97,99,104,101,115,32,40,119,104, + 101,114,101,32,105,109,112,108,101,109,101,110,116,101,100,41, + 46,218,17,105,110,118,97,108,105,100,97,116,101,95,99,97, + 99,104,101,115,78,41,5,114,8,0,0,0,218,19,112,97, + 116,104,95,105,109,112,111,114,116,101,114,95,99,97,99,104, + 101,218,6,118,97,108,117,101,115,114,112,0,0,0,114,249, + 0,0,0,41,2,114,168,0,0,0,218,6,102,105,110,100, + 101,114,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,114,249,0,0,0,34,4,0,0,115,6,0,0,0,0, + 4,16,1,10,1,122,28,80,97,116,104,70,105,110,100,101, + 114,46,105,110,118,97,108,105,100,97,116,101,95,99,97,99, + 104,101,115,99,2,0,0,0,0,0,0,0,3,0,0,0, + 12,0,0,0,67,0,0,0,115,86,0,0,0,116,0,106, + 1,100,1,107,9,114,30,116,0,106,1,12,0,114,30,116, + 2,106,3,100,2,116,4,131,2,1,0,120,50,116,0,106, + 1,68,0,93,36,125,2,121,8,124,2,124,1,131,1,83, + 0,4,0,116,5,107,10,114,72,1,0,1,0,1,0,119, + 38,89,0,113,38,88,0,113,38,87,0,100,1,83,0,100, + 1,83,0,41,3,122,46,83,101,97,114,99,104,32,115,121, + 115,46,112,97,116,104,95,104,111,111,107,115,32,102,111,114, + 32,97,32,102,105,110,100,101,114,32,102,111,114,32,39,112, + 97,116,104,39,46,78,122,23,115,121,115,46,112,97,116,104, + 95,104,111,111,107,115,32,105,115,32,101,109,112,116,121,41, + 6,114,8,0,0,0,218,10,112,97,116,104,95,104,111,111, + 107,115,114,63,0,0,0,114,64,0,0,0,114,122,0,0, + 0,114,103,0,0,0,41,3,114,168,0,0,0,114,37,0, + 0,0,90,4,104,111,111,107,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,11,95,112,97,116,104,95,104, + 111,111,107,115,42,4,0,0,115,16,0,0,0,0,3,18, + 1,12,1,12,1,2,1,8,1,14,1,12,2,122,22,80, + 97,116,104,70,105,110,100,101,114,46,95,112,97,116,104,95, + 104,111,111,107,115,99,2,0,0,0,0,0,0,0,3,0, + 0,0,19,0,0,0,67,0,0,0,115,102,0,0,0,124, + 1,100,1,107,2,114,42,121,12,116,0,106,1,131,0,125, + 1,87,0,110,20,4,0,116,2,107,10,114,40,1,0,1, + 0,1,0,100,2,83,0,88,0,121,14,116,3,106,4,124, + 1,25,0,125,2,87,0,110,40,4,0,116,5,107,10,114, + 96,1,0,1,0,1,0,124,0,106,6,124,1,131,1,125, + 2,124,2,116,3,106,4,124,1,60,0,89,0,110,2,88, + 0,124,2,83,0,41,3,122,210,71,101,116,32,116,104,101, + 32,102,105,110,100,101,114,32,102,111,114,32,116,104,101,32, + 112,97,116,104,32,101,110,116,114,121,32,102,114,111,109,32, + 115,121,115,46,112,97,116,104,95,105,109,112,111,114,116,101, + 114,95,99,97,99,104,101,46,10,10,32,32,32,32,32,32, + 32,32,73,102,32,116,104,101,32,112,97,116,104,32,101,110, + 116,114,121,32,105,115,32,110,111,116,32,105,110,32,116,104, + 101,32,99,97,99,104,101,44,32,102,105,110,100,32,116,104, + 101,32,97,112,112,114,111,112,114,105,97,116,101,32,102,105, + 110,100,101,114,10,32,32,32,32,32,32,32,32,97,110,100, + 32,99,97,99,104,101,32,105,116,46,32,73,102,32,110,111, + 32,102,105,110,100,101,114,32,105,115,32,97,118,97,105,108, + 97,98,108,101,44,32,115,116,111,114,101,32,78,111,110,101, + 46,10,10,32,32,32,32,32,32,32,32,114,32,0,0,0, + 78,41,7,114,3,0,0,0,114,47,0,0,0,218,17,70, + 105,108,101,78,111,116,70,111,117,110,100,69,114,114,111,114, + 114,8,0,0,0,114,250,0,0,0,114,135,0,0,0,114, + 254,0,0,0,41,3,114,168,0,0,0,114,37,0,0,0, + 114,252,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,218,20,95,112,97,116,104,95,105,109,112,111, + 114,116,101,114,95,99,97,99,104,101,55,4,0,0,115,22, + 0,0,0,0,8,8,1,2,1,12,1,14,3,6,1,2, + 1,14,1,14,1,10,1,16,1,122,31,80,97,116,104,70, + 105,110,100,101,114,46,95,112,97,116,104,95,105,109,112,111, + 114,116,101,114,95,99,97,99,104,101,99,3,0,0,0,0, + 0,0,0,6,0,0,0,3,0,0,0,67,0,0,0,115, + 82,0,0,0,116,0,124,2,100,1,131,2,114,26,124,2, + 106,1,124,1,131,1,92,2,125,3,125,4,110,14,124,2, + 106,2,124,1,131,1,125,3,103,0,125,4,124,3,100,0, + 107,9,114,60,116,3,106,4,124,1,124,3,131,2,83,0, + 116,3,106,5,124,1,100,0,131,2,125,5,124,4,124,5, + 95,6,124,5,83,0,41,2,78,114,121,0,0,0,41,7, + 114,112,0,0,0,114,121,0,0,0,114,179,0,0,0,114, + 118,0,0,0,114,176,0,0,0,114,158,0,0,0,114,154, + 0,0,0,41,6,114,168,0,0,0,114,123,0,0,0,114, + 252,0,0,0,114,124,0,0,0,114,125,0,0,0,114,162, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,218,16,95,108,101,103,97,99,121,95,103,101,116,95, + 115,112,101,99,77,4,0,0,115,18,0,0,0,0,4,10, + 1,16,2,10,1,4,1,8,1,12,1,12,1,6,1,122, + 27,80,97,116,104,70,105,110,100,101,114,46,95,108,101,103, + 97,99,121,95,103,101,116,95,115,112,101,99,78,99,4,0, + 0,0,0,0,0,0,9,0,0,0,5,0,0,0,67,0, + 0,0,115,170,0,0,0,103,0,125,4,120,160,124,2,68, + 0,93,130,125,5,116,0,124,5,116,1,116,2,102,2,131, + 2,115,30,113,10,124,0,106,3,124,5,131,1,125,6,124, + 6,100,1,107,9,114,10,116,4,124,6,100,2,131,2,114, + 72,124,6,106,5,124,1,124,3,131,2,125,7,110,12,124, + 0,106,6,124,1,124,6,131,2,125,7,124,7,100,1,107, + 8,114,94,113,10,124,7,106,7,100,1,107,9,114,108,124, + 7,83,0,124,7,106,8,125,8,124,8,100,1,107,8,114, + 130,116,9,100,3,131,1,130,1,124,4,106,10,124,8,131, + 1,1,0,113,10,87,0,116,11,106,12,124,1,100,1,131, + 2,125,7,124,4,124,7,95,8,124,7,83,0,100,1,83, + 0,41,4,122,63,70,105,110,100,32,116,104,101,32,108,111, + 97,100,101,114,32,111,114,32,110,97,109,101,115,112,97,99, + 101,95,112,97,116,104,32,102,111,114,32,116,104,105,115,32, + 109,111,100,117,108,101,47,112,97,99,107,97,103,101,32,110, + 97,109,101,46,78,114,178,0,0,0,122,19,115,112,101,99, + 32,109,105,115,115,105,110,103,32,108,111,97,100,101,114,41, + 13,114,141,0,0,0,114,73,0,0,0,218,5,98,121,116, + 101,115,114,0,1,0,0,114,112,0,0,0,114,178,0,0, + 0,114,1,1,0,0,114,124,0,0,0,114,154,0,0,0, + 114,103,0,0,0,114,147,0,0,0,114,118,0,0,0,114, + 158,0,0,0,41,9,114,168,0,0,0,114,123,0,0,0, + 114,37,0,0,0,114,177,0,0,0,218,14,110,97,109,101, + 115,112,97,99,101,95,112,97,116,104,90,5,101,110,116,114, + 121,114,252,0,0,0,114,162,0,0,0,114,125,0,0,0, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, + 9,95,103,101,116,95,115,112,101,99,92,4,0,0,115,40, + 0,0,0,0,5,4,1,10,1,14,1,2,1,10,1,8, + 1,10,1,14,2,12,1,8,1,2,1,10,1,4,1,6, + 1,8,1,8,5,14,2,12,1,6,1,122,20,80,97,116, + 104,70,105,110,100,101,114,46,95,103,101,116,95,115,112,101, + 99,99,4,0,0,0,0,0,0,0,6,0,0,0,4,0, + 0,0,67,0,0,0,115,100,0,0,0,124,2,100,1,107, + 8,114,14,116,0,106,1,125,2,124,0,106,2,124,1,124, + 2,124,3,131,3,125,4,124,4,100,1,107,8,114,40,100, + 1,83,0,124,4,106,3,100,1,107,8,114,92,124,4,106, + 4,125,5,124,5,114,86,100,2,124,4,95,5,116,6,124, + 1,124,5,124,0,106,2,131,3,124,4,95,4,124,4,83, + 0,100,1,83,0,110,4,124,4,83,0,100,1,83,0,41, + 3,122,141,84,114,121,32,116,111,32,102,105,110,100,32,97, + 32,115,112,101,99,32,102,111,114,32,39,102,117,108,108,110, + 97,109,101,39,32,111,110,32,115,121,115,46,112,97,116,104, + 32,111,114,32,39,112,97,116,104,39,46,10,10,32,32,32, + 32,32,32,32,32,84,104,101,32,115,101,97,114,99,104,32, + 105,115,32,98,97,115,101,100,32,111,110,32,115,121,115,46, + 112,97,116,104,95,104,111,111,107,115,32,97,110,100,32,115, + 121,115,46,112,97,116,104,95,105,109,112,111,114,116,101,114, + 95,99,97,99,104,101,46,10,32,32,32,32,32,32,32,32, + 78,90,9,110,97,109,101,115,112,97,99,101,41,7,114,8, + 0,0,0,114,37,0,0,0,114,4,1,0,0,114,124,0, + 0,0,114,154,0,0,0,114,156,0,0,0,114,227,0,0, + 0,41,6,114,168,0,0,0,114,123,0,0,0,114,37,0, + 0,0,114,177,0,0,0,114,162,0,0,0,114,3,1,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,184,0,0,0,7,4,0,0,115,2,0,0,0,0,1, - 122,25,95,78,97,109,101,115,112,97,99,101,76,111,97,100, - 101,114,46,103,101,116,95,99,111,100,101,99,2,0,0,0, - 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, - 115,4,0,0,0,100,1,83,0,41,2,122,42,85,115,101, - 32,100,101,102,97,117,108,116,32,115,101,109,97,110,116,105, - 99,115,32,102,111,114,32,109,111,100,117,108,101,32,99,114, - 101,97,116,105,111,110,46,78,114,4,0,0,0,41,2,114, - 104,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,183,0,0,0,10,4,0, - 0,115,0,0,0,0,122,30,95,78,97,109,101,115,112,97, - 99,101,76,111,97,100,101,114,46,99,114,101,97,116,101,95, - 109,111,100,117,108,101,99,2,0,0,0,0,0,0,0,2, - 0,0,0,1,0,0,0,67,0,0,0,115,4,0,0,0, - 100,0,83,0,41,1,78,114,4,0,0,0,41,2,114,104, - 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,188,0,0,0,13,4,0,0, - 115,2,0,0,0,0,1,122,28,95,78,97,109,101,115,112, - 97,99,101,76,111,97,100,101,114,46,101,120,101,99,95,109, - 111,100,117,108,101,99,2,0,0,0,0,0,0,0,2,0, - 0,0,3,0,0,0,67,0,0,0,115,26,0,0,0,116, - 0,106,1,100,1,124,0,106,2,131,2,1,0,116,0,106, - 3,124,0,124,1,131,2,83,0,41,2,122,98,76,111,97, - 100,32,97,32,110,97,109,101,115,112,97,99,101,32,109,111, - 100,117,108,101,46,10,10,32,32,32,32,32,32,32,32,84, - 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, - 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,101, - 120,101,99,95,109,111,100,117,108,101,40,41,32,105,110,115, - 116,101,97,100,46,10,10,32,32,32,32,32,32,32,32,122, - 38,110,97,109,101,115,112,97,99,101,32,109,111,100,117,108, - 101,32,108,111,97,100,101,100,32,119,105,116,104,32,112,97, - 116,104,32,123,33,114,125,41,4,114,118,0,0,0,114,133, - 0,0,0,114,229,0,0,0,114,189,0,0,0,41,2,114, - 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,190,0,0,0,16,4,0, - 0,115,6,0,0,0,0,7,6,1,8,1,122,28,95,78, - 97,109,101,115,112,97,99,101,76,111,97,100,101,114,46,108, - 111,97,100,95,109,111,100,117,108,101,78,41,12,114,109,0, - 0,0,114,108,0,0,0,114,110,0,0,0,114,182,0,0, - 0,114,180,0,0,0,114,247,0,0,0,114,157,0,0,0, - 114,199,0,0,0,114,184,0,0,0,114,183,0,0,0,114, - 188,0,0,0,114,190,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,246,0, - 0,0,244,3,0,0,115,16,0,0,0,8,1,8,3,12, - 9,8,3,8,3,8,3,8,3,8,3,114,246,0,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, - 0,64,0,0,0,115,106,0,0,0,101,0,90,1,100,0, - 90,2,100,1,90,3,101,4,100,2,100,3,132,0,131,1, - 90,5,101,4,100,4,100,5,132,0,131,1,90,6,101,4, - 100,6,100,7,132,0,131,1,90,7,101,4,100,8,100,9, - 132,0,131,1,90,8,101,4,100,17,100,11,100,12,132,1, - 131,1,90,9,101,4,100,18,100,13,100,14,132,1,131,1, - 90,10,101,4,100,19,100,15,100,16,132,1,131,1,90,11, - 100,10,83,0,41,20,218,10,80,97,116,104,70,105,110,100, - 101,114,122,62,77,101,116,97,32,112,97,116,104,32,102,105, - 110,100,101,114,32,102,111,114,32,115,121,115,46,112,97,116, - 104,32,97,110,100,32,112,97,99,107,97,103,101,32,95,95, - 112,97,116,104,95,95,32,97,116,116,114,105,98,117,116,101, - 115,46,99,1,0,0,0,0,0,0,0,2,0,0,0,4, - 0,0,0,67,0,0,0,115,42,0,0,0,120,36,116,0, - 106,1,106,2,131,0,68,0,93,22,125,1,116,3,124,1, - 100,1,131,2,114,12,124,1,106,4,131,0,1,0,113,12, - 87,0,100,2,83,0,41,3,122,125,67,97,108,108,32,116, - 104,101,32,105,110,118,97,108,105,100,97,116,101,95,99,97, - 99,104,101,115,40,41,32,109,101,116,104,111,100,32,111,110, - 32,97,108,108,32,112,97,116,104,32,101,110,116,114,121,32, - 102,105,110,100,101,114,115,10,32,32,32,32,32,32,32,32, - 115,116,111,114,101,100,32,105,110,32,115,121,115,46,112,97, - 116,104,95,105,109,112,111,114,116,101,114,95,99,97,99,104, - 101,115,32,40,119,104,101,114,101,32,105,109,112,108,101,109, - 101,110,116,101,100,41,46,218,17,105,110,118,97,108,105,100, - 97,116,101,95,99,97,99,104,101,115,78,41,5,114,8,0, - 0,0,218,19,112,97,116,104,95,105,109,112,111,114,116,101, - 114,95,99,97,99,104,101,218,6,118,97,108,117,101,115,114, - 112,0,0,0,114,249,0,0,0,41,2,114,168,0,0,0, - 218,6,102,105,110,100,101,114,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,34,4,0,0, - 115,6,0,0,0,0,4,16,1,10,1,122,28,80,97,116, - 104,70,105,110,100,101,114,46,105,110,118,97,108,105,100,97, - 116,101,95,99,97,99,104,101,115,99,2,0,0,0,0,0, - 0,0,3,0,0,0,12,0,0,0,67,0,0,0,115,86, - 0,0,0,116,0,106,1,100,1,107,9,114,30,116,0,106, - 1,12,0,114,30,116,2,106,3,100,2,116,4,131,2,1, - 0,120,50,116,0,106,1,68,0,93,36,125,2,121,8,124, - 2,124,1,131,1,83,0,4,0,116,5,107,10,114,72,1, - 0,1,0,1,0,119,38,89,0,113,38,88,0,113,38,87, - 0,100,1,83,0,100,1,83,0,41,3,122,46,83,101,97, - 114,99,104,32,115,121,115,46,112,97,116,104,95,104,111,111, - 107,115,32,102,111,114,32,97,32,102,105,110,100,101,114,32, - 102,111,114,32,39,112,97,116,104,39,46,78,122,23,115,121, - 115,46,112,97,116,104,95,104,111,111,107,115,32,105,115,32, - 101,109,112,116,121,41,6,114,8,0,0,0,218,10,112,97, - 116,104,95,104,111,111,107,115,114,63,0,0,0,114,64,0, - 0,0,114,122,0,0,0,114,103,0,0,0,41,3,114,168, - 0,0,0,114,37,0,0,0,90,4,104,111,111,107,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,95, - 112,97,116,104,95,104,111,111,107,115,42,4,0,0,115,16, - 0,0,0,0,3,18,1,12,1,12,1,2,1,8,1,14, - 1,12,2,122,22,80,97,116,104,70,105,110,100,101,114,46, - 95,112,97,116,104,95,104,111,111,107,115,99,2,0,0,0, - 0,0,0,0,3,0,0,0,19,0,0,0,67,0,0,0, - 115,102,0,0,0,124,1,100,1,107,2,114,42,121,12,116, - 0,106,1,131,0,125,1,87,0,110,20,4,0,116,2,107, - 10,114,40,1,0,1,0,1,0,100,2,83,0,88,0,121, - 14,116,3,106,4,124,1,25,0,125,2,87,0,110,40,4, - 0,116,5,107,10,114,96,1,0,1,0,1,0,124,0,106, - 6,124,1,131,1,125,2,124,2,116,3,106,4,124,1,60, - 0,89,0,110,2,88,0,124,2,83,0,41,3,122,210,71, - 101,116,32,116,104,101,32,102,105,110,100,101,114,32,102,111, - 114,32,116,104,101,32,112,97,116,104,32,101,110,116,114,121, - 32,102,114,111,109,32,115,121,115,46,112,97,116,104,95,105, - 109,112,111,114,116,101,114,95,99,97,99,104,101,46,10,10, - 32,32,32,32,32,32,32,32,73,102,32,116,104,101,32,112, - 97,116,104,32,101,110,116,114,121,32,105,115,32,110,111,116, - 32,105,110,32,116,104,101,32,99,97,99,104,101,44,32,102, - 105,110,100,32,116,104,101,32,97,112,112,114,111,112,114,105, - 97,116,101,32,102,105,110,100,101,114,10,32,32,32,32,32, - 32,32,32,97,110,100,32,99,97,99,104,101,32,105,116,46, - 32,73,102,32,110,111,32,102,105,110,100,101,114,32,105,115, - 32,97,118,97,105,108,97,98,108,101,44,32,115,116,111,114, - 101,32,78,111,110,101,46,10,10,32,32,32,32,32,32,32, - 32,114,32,0,0,0,78,41,7,114,3,0,0,0,114,47, - 0,0,0,218,17,70,105,108,101,78,111,116,70,111,117,110, - 100,69,114,114,111,114,114,8,0,0,0,114,250,0,0,0, - 114,135,0,0,0,114,254,0,0,0,41,3,114,168,0,0, - 0,114,37,0,0,0,114,252,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,218,20,95,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 55,4,0,0,115,22,0,0,0,0,8,8,1,2,1,12, - 1,14,3,6,1,2,1,14,1,14,1,10,1,16,1,122, - 31,80,97,116,104,70,105,110,100,101,114,46,95,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 99,3,0,0,0,0,0,0,0,6,0,0,0,3,0,0, - 0,67,0,0,0,115,82,0,0,0,116,0,124,2,100,1, - 131,2,114,26,124,2,106,1,124,1,131,1,92,2,125,3, - 125,4,110,14,124,2,106,2,124,1,131,1,125,3,103,0, - 125,4,124,3,100,0,107,9,114,60,116,3,106,4,124,1, - 124,3,131,2,83,0,116,3,106,5,124,1,100,0,131,2, - 125,5,124,4,124,5,95,6,124,5,83,0,41,2,78,114, - 121,0,0,0,41,7,114,112,0,0,0,114,121,0,0,0, - 114,179,0,0,0,114,118,0,0,0,114,176,0,0,0,114, - 158,0,0,0,114,154,0,0,0,41,6,114,168,0,0,0, - 114,123,0,0,0,114,252,0,0,0,114,124,0,0,0,114, - 125,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,218,16,95,108,101,103,97,99, - 121,95,103,101,116,95,115,112,101,99,77,4,0,0,115,18, - 0,0,0,0,4,10,1,16,2,10,1,4,1,8,1,12, - 1,12,1,6,1,122,27,80,97,116,104,70,105,110,100,101, - 114,46,95,108,101,103,97,99,121,95,103,101,116,95,115,112, - 101,99,78,99,4,0,0,0,0,0,0,0,9,0,0,0, - 5,0,0,0,67,0,0,0,115,170,0,0,0,103,0,125, - 4,120,160,124,2,68,0,93,130,125,5,116,0,124,5,116, - 1,116,2,102,2,131,2,115,30,113,10,124,0,106,3,124, - 5,131,1,125,6,124,6,100,1,107,9,114,10,116,4,124, - 6,100,2,131,2,114,72,124,6,106,5,124,1,124,3,131, - 2,125,7,110,12,124,0,106,6,124,1,124,6,131,2,125, - 7,124,7,100,1,107,8,114,94,113,10,124,7,106,7,100, - 1,107,9,114,108,124,7,83,0,124,7,106,8,125,8,124, - 8,100,1,107,8,114,130,116,9,100,3,131,1,130,1,124, - 4,106,10,124,8,131,1,1,0,113,10,87,0,116,11,106, - 12,124,1,100,1,131,2,125,7,124,4,124,7,95,8,124, - 7,83,0,100,1,83,0,41,4,122,63,70,105,110,100,32, - 116,104,101,32,108,111,97,100,101,114,32,111,114,32,110,97, - 109,101,115,112,97,99,101,95,112,97,116,104,32,102,111,114, - 32,116,104,105,115,32,109,111,100,117,108,101,47,112,97,99, - 107,97,103,101,32,110,97,109,101,46,78,114,178,0,0,0, - 122,19,115,112,101,99,32,109,105,115,115,105,110,103,32,108, - 111,97,100,101,114,41,13,114,141,0,0,0,114,73,0,0, - 0,218,5,98,121,116,101,115,114,0,1,0,0,114,112,0, - 0,0,114,178,0,0,0,114,1,1,0,0,114,124,0,0, - 0,114,154,0,0,0,114,103,0,0,0,114,147,0,0,0, - 114,118,0,0,0,114,158,0,0,0,41,9,114,168,0,0, - 0,114,123,0,0,0,114,37,0,0,0,114,177,0,0,0, - 218,14,110,97,109,101,115,112,97,99,101,95,112,97,116,104, - 90,5,101,110,116,114,121,114,252,0,0,0,114,162,0,0, - 0,114,125,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,218,9,95,103,101,116,95,115,112,101,99, - 92,4,0,0,115,40,0,0,0,0,5,4,1,10,1,14, - 1,2,1,10,1,8,1,10,1,14,2,12,1,8,1,2, - 1,10,1,4,1,6,1,8,1,8,5,14,2,12,1,6, - 1,122,20,80,97,116,104,70,105,110,100,101,114,46,95,103, - 101,116,95,115,112,101,99,99,4,0,0,0,0,0,0,0, - 6,0,0,0,4,0,0,0,67,0,0,0,115,104,0,0, - 0,124,2,100,1,107,8,114,14,116,0,106,1,125,2,124, - 0,106,2,124,1,124,2,124,3,131,3,125,4,124,4,100, - 1,107,8,114,42,100,1,83,0,110,58,124,4,106,3,100, - 1,107,8,114,96,124,4,106,4,125,5,124,5,114,90,100, - 2,124,4,95,5,116,6,124,1,124,5,124,0,106,2,131, - 3,124,4,95,4,124,4,83,0,113,100,100,1,83,0,110, - 4,124,4,83,0,100,1,83,0,41,3,122,141,84,114,121, - 32,116,111,32,102,105,110,100,32,97,32,115,112,101,99,32, - 102,111,114,32,39,102,117,108,108,110,97,109,101,39,32,111, - 110,32,115,121,115,46,112,97,116,104,32,111,114,32,39,112, - 97,116,104,39,46,10,10,32,32,32,32,32,32,32,32,84, - 104,101,32,115,101,97,114,99,104,32,105,115,32,98,97,115, - 101,100,32,111,110,32,115,121,115,46,112,97,116,104,95,104, - 111,111,107,115,32,97,110,100,32,115,121,115,46,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 46,10,32,32,32,32,32,32,32,32,78,90,9,110,97,109, - 101,115,112,97,99,101,41,7,114,8,0,0,0,114,37,0, - 0,0,114,4,1,0,0,114,124,0,0,0,114,154,0,0, - 0,114,156,0,0,0,114,227,0,0,0,41,6,114,168,0, - 0,0,114,123,0,0,0,114,37,0,0,0,114,177,0,0, - 0,114,162,0,0,0,114,3,1,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,124, - 4,0,0,115,26,0,0,0,0,6,8,1,6,1,14,1, - 8,1,6,1,10,1,6,1,4,3,6,1,16,1,6,2, - 6,2,122,20,80,97,116,104,70,105,110,100,101,114,46,102, - 105,110,100,95,115,112,101,99,99,3,0,0,0,0,0,0, - 0,4,0,0,0,3,0,0,0,67,0,0,0,115,30,0, - 0,0,124,0,106,0,124,1,124,2,131,2,125,3,124,3, - 100,1,107,8,114,24,100,1,83,0,124,3,106,1,83,0, - 41,2,122,170,102,105,110,100,32,116,104,101,32,109,111,100, - 117,108,101,32,111,110,32,115,121,115,46,112,97,116,104,32, - 111,114,32,39,112,97,116,104,39,32,98,97,115,101,100,32, - 111,110,32,115,121,115,46,112,97,116,104,95,104,111,111,107, - 115,32,97,110,100,10,32,32,32,32,32,32,32,32,115,121, - 115,46,112,97,116,104,95,105,109,112,111,114,116,101,114,95, - 99,97,99,104,101,46,10,10,32,32,32,32,32,32,32,32, - 84,104,105,115,32,109,101,116,104,111,100,32,105,115,32,100, - 101,112,114,101,99,97,116,101,100,46,32,32,85,115,101,32, - 102,105,110,100,95,115,112,101,99,40,41,32,105,110,115,116, - 101,97,100,46,10,10,32,32,32,32,32,32,32,32,78,41, - 2,114,178,0,0,0,114,124,0,0,0,41,4,114,168,0, - 0,0,114,123,0,0,0,114,37,0,0,0,114,162,0,0, + 114,178,0,0,0,124,4,0,0,115,26,0,0,0,0,6, + 8,1,6,1,14,1,8,1,4,1,10,1,6,1,4,3, + 6,1,16,1,4,2,6,2,122,20,80,97,116,104,70,105, + 110,100,101,114,46,102,105,110,100,95,115,112,101,99,99,3, + 0,0,0,0,0,0,0,4,0,0,0,3,0,0,0,67, + 0,0,0,115,30,0,0,0,124,0,106,0,124,1,124,2, + 131,2,125,3,124,3,100,1,107,8,114,24,100,1,83,0, + 124,3,106,1,83,0,41,2,122,170,102,105,110,100,32,116, + 104,101,32,109,111,100,117,108,101,32,111,110,32,115,121,115, + 46,112,97,116,104,32,111,114,32,39,112,97,116,104,39,32, + 98,97,115,101,100,32,111,110,32,115,121,115,46,112,97,116, + 104,95,104,111,111,107,115,32,97,110,100,10,32,32,32,32, + 32,32,32,32,115,121,115,46,112,97,116,104,95,105,109,112, + 111,114,116,101,114,95,99,97,99,104,101,46,10,10,32,32, + 32,32,32,32,32,32,84,104,105,115,32,109,101,116,104,111, + 100,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46, + 32,32,85,115,101,32,102,105,110,100,95,115,112,101,99,40, + 41,32,105,110,115,116,101,97,100,46,10,10,32,32,32,32, + 32,32,32,32,78,41,2,114,178,0,0,0,114,124,0,0, + 0,41,4,114,168,0,0,0,114,123,0,0,0,114,37,0, + 0,0,114,162,0,0,0,114,4,0,0,0,114,4,0,0, + 0,114,6,0,0,0,114,179,0,0,0,148,4,0,0,115, + 8,0,0,0,0,8,12,1,8,1,4,1,122,22,80,97, + 116,104,70,105,110,100,101,114,46,102,105,110,100,95,109,111, + 100,117,108,101,41,1,78,41,2,78,78,41,1,78,41,12, + 114,109,0,0,0,114,108,0,0,0,114,110,0,0,0,114, + 111,0,0,0,114,180,0,0,0,114,249,0,0,0,114,254, + 0,0,0,114,0,1,0,0,114,1,1,0,0,114,4,1, + 0,0,114,178,0,0,0,114,179,0,0,0,114,4,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,179,0,0,0,148,4,0,0,115,8,0,0,0,0,8, - 12,1,8,1,4,1,122,22,80,97,116,104,70,105,110,100, - 101,114,46,102,105,110,100,95,109,111,100,117,108,101,41,1, - 78,41,2,78,78,41,1,78,41,12,114,109,0,0,0,114, - 108,0,0,0,114,110,0,0,0,114,111,0,0,0,114,180, - 0,0,0,114,249,0,0,0,114,254,0,0,0,114,0,1, - 0,0,114,1,1,0,0,114,4,1,0,0,114,178,0,0, - 0,114,179,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,248,0,0,0,30, - 4,0,0,115,22,0,0,0,8,2,4,2,12,8,12,13, - 12,22,12,15,2,1,12,31,2,1,12,23,2,1,114,248, - 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0, - 3,0,0,0,64,0,0,0,115,90,0,0,0,101,0,90, - 1,100,0,90,2,100,1,90,3,100,2,100,3,132,0,90, - 4,100,4,100,5,132,0,90,5,101,6,90,7,100,6,100, - 7,132,0,90,8,100,8,100,9,132,0,90,9,100,19,100, - 11,100,12,132,1,90,10,100,13,100,14,132,0,90,11,101, - 12,100,15,100,16,132,0,131,1,90,13,100,17,100,18,132, - 0,90,14,100,10,83,0,41,20,218,10,70,105,108,101,70, - 105,110,100,101,114,122,172,70,105,108,101,45,98,97,115,101, - 100,32,102,105,110,100,101,114,46,10,10,32,32,32,32,73, - 110,116,101,114,97,99,116,105,111,110,115,32,119,105,116,104, - 32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109, - 32,97,114,101,32,99,97,99,104,101,100,32,102,111,114,32, - 112,101,114,102,111,114,109,97,110,99,101,44,32,98,101,105, - 110,103,10,32,32,32,32,114,101,102,114,101,115,104,101,100, - 32,119,104,101,110,32,116,104,101,32,100,105,114,101,99,116, - 111,114,121,32,116,104,101,32,102,105,110,100,101,114,32,105, - 115,32,104,97,110,100,108,105,110,103,32,104,97,115,32,98, - 101,101,110,32,109,111,100,105,102,105,101,100,46,10,10,32, - 32,32,32,99,2,0,0,0,0,0,0,0,5,0,0,0, - 5,0,0,0,7,0,0,0,115,88,0,0,0,103,0,125, - 3,120,40,124,2,68,0,93,32,92,2,137,0,125,4,124, - 3,106,0,135,0,102,1,100,1,100,2,132,8,124,4,68, - 0,131,1,131,1,1,0,113,10,87,0,124,3,124,0,95, - 1,124,1,112,58,100,3,124,0,95,2,100,6,124,0,95, - 3,116,4,131,0,124,0,95,5,116,4,131,0,124,0,95, - 6,100,5,83,0,41,7,122,154,73,110,105,116,105,97,108, - 105,122,101,32,119,105,116,104,32,116,104,101,32,112,97,116, - 104,32,116,111,32,115,101,97,114,99,104,32,111,110,32,97, - 110,100,32,97,32,118,97,114,105,97,98,108,101,32,110,117, - 109,98,101,114,32,111,102,10,32,32,32,32,32,32,32,32, - 50,45,116,117,112,108,101,115,32,99,111,110,116,97,105,110, - 105,110,103,32,116,104,101,32,108,111,97,100,101,114,32,97, - 110,100,32,116,104,101,32,102,105,108,101,32,115,117,102,102, - 105,120,101,115,32,116,104,101,32,108,111,97,100,101,114,10, - 32,32,32,32,32,32,32,32,114,101,99,111,103,110,105,122, - 101,115,46,99,1,0,0,0,0,0,0,0,2,0,0,0, - 3,0,0,0,51,0,0,0,115,22,0,0,0,124,0,93, - 14,125,1,124,1,136,0,102,2,86,0,1,0,113,2,100, - 0,83,0,41,1,78,114,4,0,0,0,41,2,114,24,0, - 0,0,114,222,0,0,0,41,1,114,124,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,224,0,0,0,177,4,0, - 0,115,2,0,0,0,4,0,122,38,70,105,108,101,70,105, - 110,100,101,114,46,95,95,105,110,105,116,95,95,46,60,108, - 111,99,97,108,115,62,46,60,103,101,110,101,120,112,114,62, - 114,61,0,0,0,114,31,0,0,0,78,114,91,0,0,0, - 41,7,114,147,0,0,0,218,8,95,108,111,97,100,101,114, - 115,114,37,0,0,0,218,11,95,112,97,116,104,95,109,116, - 105,109,101,218,3,115,101,116,218,11,95,112,97,116,104,95, - 99,97,99,104,101,218,19,95,114,101,108,97,120,101,100,95, - 112,97,116,104,95,99,97,99,104,101,41,5,114,104,0,0, - 0,114,37,0,0,0,218,14,108,111,97,100,101,114,95,100, - 101,116,97,105,108,115,90,7,108,111,97,100,101,114,115,114, - 164,0,0,0,114,4,0,0,0,41,1,114,124,0,0,0, - 114,6,0,0,0,114,182,0,0,0,171,4,0,0,115,16, - 0,0,0,0,4,4,1,14,1,28,1,6,2,10,1,6, - 1,8,1,122,19,70,105,108,101,70,105,110,100,101,114,46, - 95,95,105,110,105,116,95,95,99,1,0,0,0,0,0,0, - 0,1,0,0,0,2,0,0,0,67,0,0,0,115,10,0, - 0,0,100,3,124,0,95,0,100,2,83,0,41,4,122,31, - 73,110,118,97,108,105,100,97,116,101,32,116,104,101,32,100, - 105,114,101,99,116,111,114,121,32,109,116,105,109,101,46,114, - 31,0,0,0,78,114,91,0,0,0,41,1,114,7,1,0, - 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,185,4,0,0, - 115,2,0,0,0,0,2,122,28,70,105,108,101,70,105,110, - 100,101,114,46,105,110,118,97,108,105,100,97,116,101,95,99, - 97,99,104,101,115,99,2,0,0,0,0,0,0,0,3,0, - 0,0,2,0,0,0,67,0,0,0,115,42,0,0,0,124, - 0,106,0,124,1,131,1,125,2,124,2,100,1,107,8,114, - 26,100,1,103,0,102,2,83,0,124,2,106,1,124,2,106, - 2,112,38,103,0,102,2,83,0,41,2,122,197,84,114,121, - 32,116,111,32,102,105,110,100,32,97,32,108,111,97,100,101, - 114,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102, - 105,101,100,32,109,111,100,117,108,101,44,32,111,114,32,116, - 104,101,32,110,97,109,101,115,112,97,99,101,10,32,32,32, - 32,32,32,32,32,112,97,99,107,97,103,101,32,112,111,114, - 116,105,111,110,115,46,32,82,101,116,117,114,110,115,32,40, - 108,111,97,100,101,114,44,32,108,105,115,116,45,111,102,45, - 112,111,114,116,105,111,110,115,41,46,10,10,32,32,32,32, - 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32, - 105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,32, - 85,115,101,32,102,105,110,100,95,115,112,101,99,40,41,32, - 105,110,115,116,101,97,100,46,10,10,32,32,32,32,32,32, - 32,32,78,41,3,114,178,0,0,0,114,124,0,0,0,114, - 154,0,0,0,41,3,114,104,0,0,0,114,123,0,0,0, - 114,162,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,121,0,0,0,191,4,0,0,115,8,0, - 0,0,0,7,10,1,8,1,8,1,122,22,70,105,108,101, - 70,105,110,100,101,114,46,102,105,110,100,95,108,111,97,100, - 101,114,99,6,0,0,0,0,0,0,0,7,0,0,0,6, - 0,0,0,67,0,0,0,115,26,0,0,0,124,1,124,2, - 124,3,131,2,125,6,116,0,124,2,124,3,124,6,124,4, - 100,1,141,4,83,0,41,2,78,41,2,114,124,0,0,0, - 114,154,0,0,0,41,1,114,165,0,0,0,41,7,114,104, - 0,0,0,114,163,0,0,0,114,123,0,0,0,114,37,0, - 0,0,90,4,115,109,115,108,114,177,0,0,0,114,124,0, - 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,4,1,0,0,203,4,0,0,115,6,0,0,0,0, - 1,10,1,8,1,122,20,70,105,108,101,70,105,110,100,101, - 114,46,95,103,101,116,95,115,112,101,99,78,99,3,0,0, - 0,0,0,0,0,14,0,0,0,15,0,0,0,67,0,0, - 0,115,98,1,0,0,100,1,125,3,124,1,106,0,100,2, - 131,1,100,3,25,0,125,4,121,24,116,1,124,0,106,2, - 112,34,116,3,106,4,131,0,131,1,106,5,125,5,87,0, - 110,24,4,0,116,6,107,10,114,66,1,0,1,0,1,0, - 100,10,125,5,89,0,110,2,88,0,124,5,124,0,106,7, - 107,3,114,92,124,0,106,8,131,0,1,0,124,5,124,0, - 95,7,116,9,131,0,114,114,124,0,106,10,125,6,124,4, - 106,11,131,0,125,7,110,10,124,0,106,12,125,6,124,4, - 125,7,124,7,124,6,107,6,114,218,116,13,124,0,106,2, - 124,4,131,2,125,8,120,72,124,0,106,14,68,0,93,54, - 92,2,125,9,125,10,100,5,124,9,23,0,125,11,116,13, - 124,8,124,11,131,2,125,12,116,15,124,12,131,1,114,152, - 124,0,106,16,124,10,124,1,124,12,124,8,103,1,124,2, - 131,5,83,0,113,152,87,0,116,17,124,8,131,1,125,3, - 120,88,124,0,106,14,68,0,93,78,92,2,125,9,125,10, - 116,13,124,0,106,2,124,4,124,9,23,0,131,2,125,12, - 116,18,106,19,100,6,124,12,100,3,100,7,141,3,1,0, - 124,7,124,9,23,0,124,6,107,6,114,226,116,15,124,12, - 131,1,114,226,124,0,106,16,124,10,124,1,124,12,100,8, - 124,2,131,5,83,0,113,226,87,0,124,3,144,1,114,94, - 116,18,106,19,100,9,124,8,131,2,1,0,116,18,106,20, - 124,1,100,8,131,2,125,13,124,8,103,1,124,13,95,21, - 124,13,83,0,100,8,83,0,41,11,122,111,84,114,121,32, - 116,111,32,102,105,110,100,32,97,32,115,112,101,99,32,102, - 111,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100, - 32,109,111,100,117,108,101,46,10,10,32,32,32,32,32,32, - 32,32,82,101,116,117,114,110,115,32,116,104,101,32,109,97, - 116,99,104,105,110,103,32,115,112,101,99,44,32,111,114,32, - 78,111,110,101,32,105,102,32,110,111,116,32,102,111,117,110, - 100,46,10,32,32,32,32,32,32,32,32,70,114,61,0,0, - 0,114,59,0,0,0,114,31,0,0,0,114,182,0,0,0, - 122,9,116,114,121,105,110,103,32,123,125,41,1,90,9,118, - 101,114,98,111,115,105,116,121,78,122,25,112,111,115,115,105, - 98,108,101,32,110,97,109,101,115,112,97,99,101,32,102,111, - 114,32,123,125,114,91,0,0,0,41,22,114,34,0,0,0, - 114,41,0,0,0,114,37,0,0,0,114,3,0,0,0,114, - 47,0,0,0,114,216,0,0,0,114,42,0,0,0,114,7, - 1,0,0,218,11,95,102,105,108,108,95,99,97,99,104,101, - 114,7,0,0,0,114,10,1,0,0,114,92,0,0,0,114, - 9,1,0,0,114,30,0,0,0,114,6,1,0,0,114,46, - 0,0,0,114,4,1,0,0,114,48,0,0,0,114,118,0, - 0,0,114,133,0,0,0,114,158,0,0,0,114,154,0,0, - 0,41,14,114,104,0,0,0,114,123,0,0,0,114,177,0, - 0,0,90,12,105,115,95,110,97,109,101,115,112,97,99,101, - 90,11,116,97,105,108,95,109,111,100,117,108,101,114,130,0, - 0,0,90,5,99,97,99,104,101,90,12,99,97,99,104,101, - 95,109,111,100,117,108,101,90,9,98,97,115,101,95,112,97, - 116,104,114,222,0,0,0,114,163,0,0,0,90,13,105,110, - 105,116,95,102,105,108,101,110,97,109,101,90,9,102,117,108, - 108,95,112,97,116,104,114,162,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,208, - 4,0,0,115,70,0,0,0,0,5,4,1,14,1,2,1, - 24,1,14,1,10,1,10,1,8,1,6,2,6,1,6,1, - 10,2,6,1,4,2,8,1,12,1,16,1,8,1,10,1, - 8,1,24,4,8,2,16,1,16,1,16,1,12,1,8,1, - 10,1,12,1,6,1,12,1,12,1,8,1,4,1,122,20, - 70,105,108,101,70,105,110,100,101,114,46,102,105,110,100,95, - 115,112,101,99,99,1,0,0,0,0,0,0,0,9,0,0, - 0,13,0,0,0,67,0,0,0,115,194,0,0,0,124,0, - 106,0,125,1,121,22,116,1,106,2,124,1,112,22,116,1, - 106,3,131,0,131,1,125,2,87,0,110,30,4,0,116,4, - 116,5,116,6,102,3,107,10,114,58,1,0,1,0,1,0, - 103,0,125,2,89,0,110,2,88,0,116,7,106,8,106,9, - 100,1,131,1,115,84,116,10,124,2,131,1,124,0,95,11, - 110,78,116,10,131,0,125,3,120,64,124,2,68,0,93,56, - 125,4,124,4,106,12,100,2,131,1,92,3,125,5,125,6, - 125,7,124,6,114,138,100,3,106,13,124,5,124,7,106,14, - 131,0,131,2,125,8,110,4,124,5,125,8,124,3,106,15, - 124,8,131,1,1,0,113,96,87,0,124,3,124,0,95,11, - 116,7,106,8,106,9,116,16,131,1,114,190,100,4,100,5, - 132,0,124,2,68,0,131,1,124,0,95,17,100,6,83,0, - 41,7,122,68,70,105,108,108,32,116,104,101,32,99,97,99, - 104,101,32,111,102,32,112,111,116,101,110,116,105,97,108,32, - 109,111,100,117,108,101,115,32,97,110,100,32,112,97,99,107, - 97,103,101,115,32,102,111,114,32,116,104,105,115,32,100,105, - 114,101,99,116,111,114,121,46,114,0,0,0,0,114,61,0, - 0,0,122,5,123,125,46,123,125,99,1,0,0,0,0,0, - 0,0,2,0,0,0,3,0,0,0,83,0,0,0,115,20, - 0,0,0,104,0,124,0,93,12,125,1,124,1,106,0,131, - 0,146,2,113,4,83,0,114,4,0,0,0,41,1,114,92, - 0,0,0,41,2,114,24,0,0,0,90,2,102,110,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,250,9,60, - 115,101,116,99,111,109,112,62,29,5,0,0,115,2,0,0, - 0,6,0,122,41,70,105,108,101,70,105,110,100,101,114,46, - 95,102,105,108,108,95,99,97,99,104,101,46,60,108,111,99, - 97,108,115,62,46,60,115,101,116,99,111,109,112,62,78,41, - 18,114,37,0,0,0,114,3,0,0,0,90,7,108,105,115, - 116,100,105,114,114,47,0,0,0,114,255,0,0,0,218,15, - 80,101,114,109,105,115,115,105,111,110,69,114,114,111,114,218, - 18,78,111,116,65,68,105,114,101,99,116,111,114,121,69,114, - 114,111,114,114,8,0,0,0,114,9,0,0,0,114,10,0, - 0,0,114,8,1,0,0,114,9,1,0,0,114,87,0,0, - 0,114,50,0,0,0,114,92,0,0,0,218,3,97,100,100, - 114,11,0,0,0,114,10,1,0,0,41,9,114,104,0,0, - 0,114,37,0,0,0,90,8,99,111,110,116,101,110,116,115, - 90,21,108,111,119,101,114,95,115,117,102,102,105,120,95,99, - 111,110,116,101,110,116,115,114,244,0,0,0,114,102,0,0, - 0,114,234,0,0,0,114,222,0,0,0,90,8,110,101,119, - 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,12,1,0,0,0,5,0,0,115,34,0, - 0,0,0,2,6,1,2,1,22,1,20,3,10,3,12,1, - 12,7,6,1,10,1,16,1,4,1,18,2,4,1,14,1, - 6,1,12,1,122,22,70,105,108,101,70,105,110,100,101,114, - 46,95,102,105,108,108,95,99,97,99,104,101,99,1,0,0, - 0,0,0,0,0,3,0,0,0,3,0,0,0,7,0,0, - 0,115,18,0,0,0,135,0,135,1,102,2,100,1,100,2, - 132,8,125,2,124,2,83,0,41,3,97,20,1,0,0,65, - 32,99,108,97,115,115,32,109,101,116,104,111,100,32,119,104, - 105,99,104,32,114,101,116,117,114,110,115,32,97,32,99,108, - 111,115,117,114,101,32,116,111,32,117,115,101,32,111,110,32, - 115,121,115,46,112,97,116,104,95,104,111,111,107,10,32,32, - 32,32,32,32,32,32,119,104,105,99,104,32,119,105,108,108, - 32,114,101,116,117,114,110,32,97,110,32,105,110,115,116,97, - 110,99,101,32,117,115,105,110,103,32,116,104,101,32,115,112, - 101,99,105,102,105,101,100,32,108,111,97,100,101,114,115,32, - 97,110,100,32,116,104,101,32,112,97,116,104,10,32,32,32, - 32,32,32,32,32,99,97,108,108,101,100,32,111,110,32,116, - 104,101,32,99,108,111,115,117,114,101,46,10,10,32,32,32, - 32,32,32,32,32,73,102,32,116,104,101,32,112,97,116,104, - 32,99,97,108,108,101,100,32,111,110,32,116,104,101,32,99, - 108,111,115,117,114,101,32,105,115,32,110,111,116,32,97,32, - 100,105,114,101,99,116,111,114,121,44,32,73,109,112,111,114, - 116,69,114,114,111,114,32,105,115,10,32,32,32,32,32,32, - 32,32,114,97,105,115,101,100,46,10,10,32,32,32,32,32, - 32,32,32,99,1,0,0,0,0,0,0,0,1,0,0,0, - 4,0,0,0,19,0,0,0,115,34,0,0,0,116,0,124, - 0,131,1,115,20,116,1,100,1,124,0,100,2,141,2,130, - 1,136,0,124,0,102,1,136,1,158,2,142,0,83,0,41, - 3,122,45,80,97,116,104,32,104,111,111,107,32,102,111,114, - 32,105,109,112,111,114,116,108,105,98,46,109,97,99,104,105, - 110,101,114,121,46,70,105,108,101,70,105,110,100,101,114,46, - 122,30,111,110,108,121,32,100,105,114,101,99,116,111,114,105, - 101,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100, - 41,1,114,37,0,0,0,41,2,114,48,0,0,0,114,103, - 0,0,0,41,1,114,37,0,0,0,41,2,114,168,0,0, - 0,114,11,1,0,0,114,4,0,0,0,114,6,0,0,0, - 218,24,112,97,116,104,95,104,111,111,107,95,102,111,114,95, - 70,105,108,101,70,105,110,100,101,114,41,5,0,0,115,6, - 0,0,0,0,2,8,1,12,1,122,54,70,105,108,101,70, - 105,110,100,101,114,46,112,97,116,104,95,104,111,111,107,46, - 60,108,111,99,97,108,115,62,46,112,97,116,104,95,104,111, - 111,107,95,102,111,114,95,70,105,108,101,70,105,110,100,101, - 114,114,4,0,0,0,41,3,114,168,0,0,0,114,11,1, - 0,0,114,17,1,0,0,114,4,0,0,0,41,2,114,168, - 0,0,0,114,11,1,0,0,114,6,0,0,0,218,9,112, - 97,116,104,95,104,111,111,107,31,5,0,0,115,4,0,0, - 0,0,10,14,6,122,20,70,105,108,101,70,105,110,100,101, - 114,46,112,97,116,104,95,104,111,111,107,99,1,0,0,0, - 0,0,0,0,1,0,0,0,2,0,0,0,67,0,0,0, - 115,12,0,0,0,100,1,106,0,124,0,106,1,131,1,83, - 0,41,2,78,122,16,70,105,108,101,70,105,110,100,101,114, - 40,123,33,114,125,41,41,2,114,50,0,0,0,114,37,0, - 0,0,41,1,114,104,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,243,0,0,0,49,5,0, - 0,115,2,0,0,0,0,1,122,19,70,105,108,101,70,105, - 110,100,101,114,46,95,95,114,101,112,114,95,95,41,1,78, - 41,15,114,109,0,0,0,114,108,0,0,0,114,110,0,0, - 0,114,111,0,0,0,114,182,0,0,0,114,249,0,0,0, - 114,127,0,0,0,114,179,0,0,0,114,121,0,0,0,114, - 4,1,0,0,114,178,0,0,0,114,12,1,0,0,114,180, - 0,0,0,114,18,1,0,0,114,243,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,5,1,0,0,162,4,0,0,115,20,0,0,0,8, - 7,4,2,8,14,8,4,4,2,8,12,8,5,10,48,8, - 31,12,18,114,5,1,0,0,99,4,0,0,0,0,0,0, - 0,6,0,0,0,11,0,0,0,67,0,0,0,115,146,0, - 0,0,124,0,106,0,100,1,131,1,125,4,124,0,106,0, - 100,2,131,1,125,5,124,4,115,66,124,5,114,36,124,5, - 106,1,125,4,110,30,124,2,124,3,107,2,114,56,116,2, - 124,1,124,2,131,2,125,4,110,10,116,3,124,1,124,2, - 131,2,125,4,124,5,115,84,116,4,124,1,124,2,124,4, - 100,3,141,3,125,5,121,36,124,5,124,0,100,2,60,0, - 124,4,124,0,100,1,60,0,124,2,124,0,100,4,60,0, - 124,3,124,0,100,5,60,0,87,0,110,20,4,0,116,5, - 107,10,114,140,1,0,1,0,1,0,89,0,110,2,88,0, - 100,0,83,0,41,6,78,218,10,95,95,108,111,97,100,101, - 114,95,95,218,8,95,95,115,112,101,99,95,95,41,1,114, - 124,0,0,0,90,8,95,95,102,105,108,101,95,95,90,10, - 95,95,99,97,99,104,101,100,95,95,41,6,218,3,103,101, - 116,114,124,0,0,0,114,220,0,0,0,114,215,0,0,0, - 114,165,0,0,0,218,9,69,120,99,101,112,116,105,111,110, - 41,6,90,2,110,115,114,102,0,0,0,90,8,112,97,116, - 104,110,97,109,101,90,9,99,112,97,116,104,110,97,109,101, - 114,124,0,0,0,114,162,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,218,14,95,102,105,120,95, - 117,112,95,109,111,100,117,108,101,55,5,0,0,115,34,0, - 0,0,0,2,10,1,10,1,4,1,4,1,8,1,8,1, - 12,2,10,1,4,1,14,1,2,1,8,1,8,1,8,1, - 12,1,14,2,114,23,1,0,0,99,0,0,0,0,0,0, - 0,0,3,0,0,0,3,0,0,0,67,0,0,0,115,38, - 0,0,0,116,0,116,1,106,2,131,0,102,2,125,0,116, - 3,116,4,102,2,125,1,116,5,116,6,102,2,125,2,124, - 0,124,1,124,2,103,3,83,0,41,1,122,95,82,101,116, - 117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,102, - 105,108,101,45,98,97,115,101,100,32,109,111,100,117,108,101, - 32,108,111,97,100,101,114,115,46,10,10,32,32,32,32,69, - 97,99,104,32,105,116,101,109,32,105,115,32,97,32,116,117, - 112,108,101,32,40,108,111,97,100,101,114,44,32,115,117,102, - 102,105,120,101,115,41,46,10,32,32,32,32,41,7,114,221, - 0,0,0,114,143,0,0,0,218,18,101,120,116,101,110,115, - 105,111,110,95,115,117,102,102,105,120,101,115,114,215,0,0, - 0,114,88,0,0,0,114,220,0,0,0,114,78,0,0,0, - 41,3,90,10,101,120,116,101,110,115,105,111,110,115,90,6, - 115,111,117,114,99,101,90,8,98,121,116,101,99,111,100,101, + 114,248,0,0,0,30,4,0,0,115,22,0,0,0,8,2, + 4,2,12,8,12,13,12,22,12,15,2,1,12,31,2,1, + 12,23,2,1,114,248,0,0,0,99,0,0,0,0,0,0, + 0,0,0,0,0,0,3,0,0,0,64,0,0,0,115,90, + 0,0,0,101,0,90,1,100,0,90,2,100,1,90,3,100, + 2,100,3,132,0,90,4,100,4,100,5,132,0,90,5,101, + 6,90,7,100,6,100,7,132,0,90,8,100,8,100,9,132, + 0,90,9,100,19,100,11,100,12,132,1,90,10,100,13,100, + 14,132,0,90,11,101,12,100,15,100,16,132,0,131,1,90, + 13,100,17,100,18,132,0,90,14,100,10,83,0,41,20,218, + 10,70,105,108,101,70,105,110,100,101,114,122,172,70,105,108, + 101,45,98,97,115,101,100,32,102,105,110,100,101,114,46,10, + 10,32,32,32,32,73,110,116,101,114,97,99,116,105,111,110, + 115,32,119,105,116,104,32,116,104,101,32,102,105,108,101,32, + 115,121,115,116,101,109,32,97,114,101,32,99,97,99,104,101, + 100,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99, + 101,44,32,98,101,105,110,103,10,32,32,32,32,114,101,102, + 114,101,115,104,101,100,32,119,104,101,110,32,116,104,101,32, + 100,105,114,101,99,116,111,114,121,32,116,104,101,32,102,105, + 110,100,101,114,32,105,115,32,104,97,110,100,108,105,110,103, + 32,104,97,115,32,98,101,101,110,32,109,111,100,105,102,105, + 101,100,46,10,10,32,32,32,32,99,2,0,0,0,0,0, + 0,0,5,0,0,0,5,0,0,0,7,0,0,0,115,88, + 0,0,0,103,0,125,3,120,40,124,2,68,0,93,32,92, + 2,137,0,125,4,124,3,106,0,135,0,102,1,100,1,100, + 2,132,8,124,4,68,0,131,1,131,1,1,0,113,10,87, + 0,124,3,124,0,95,1,124,1,112,58,100,3,124,0,95, + 2,100,6,124,0,95,3,116,4,131,0,124,0,95,5,116, + 4,131,0,124,0,95,6,100,5,83,0,41,7,122,154,73, + 110,105,116,105,97,108,105,122,101,32,119,105,116,104,32,116, + 104,101,32,112,97,116,104,32,116,111,32,115,101,97,114,99, + 104,32,111,110,32,97,110,100,32,97,32,118,97,114,105,97, + 98,108,101,32,110,117,109,98,101,114,32,111,102,10,32,32, + 32,32,32,32,32,32,50,45,116,117,112,108,101,115,32,99, + 111,110,116,97,105,110,105,110,103,32,116,104,101,32,108,111, + 97,100,101,114,32,97,110,100,32,116,104,101,32,102,105,108, + 101,32,115,117,102,102,105,120,101,115,32,116,104,101,32,108, + 111,97,100,101,114,10,32,32,32,32,32,32,32,32,114,101, + 99,111,103,110,105,122,101,115,46,99,1,0,0,0,0,0, + 0,0,2,0,0,0,3,0,0,0,51,0,0,0,115,22, + 0,0,0,124,0,93,14,125,1,124,1,136,0,102,2,86, + 0,1,0,113,2,100,0,83,0,41,1,78,114,4,0,0, + 0,41,2,114,24,0,0,0,114,222,0,0,0,41,1,114, + 124,0,0,0,114,4,0,0,0,114,6,0,0,0,114,224, + 0,0,0,177,4,0,0,115,2,0,0,0,4,0,122,38, + 70,105,108,101,70,105,110,100,101,114,46,95,95,105,110,105, + 116,95,95,46,60,108,111,99,97,108,115,62,46,60,103,101, + 110,101,120,112,114,62,114,61,0,0,0,114,31,0,0,0, + 78,114,91,0,0,0,41,7,114,147,0,0,0,218,8,95, + 108,111,97,100,101,114,115,114,37,0,0,0,218,11,95,112, + 97,116,104,95,109,116,105,109,101,218,3,115,101,116,218,11, + 95,112,97,116,104,95,99,97,99,104,101,218,19,95,114,101, + 108,97,120,101,100,95,112,97,116,104,95,99,97,99,104,101, + 41,5,114,104,0,0,0,114,37,0,0,0,218,14,108,111, + 97,100,101,114,95,100,101,116,97,105,108,115,90,7,108,111, + 97,100,101,114,115,114,164,0,0,0,114,4,0,0,0,41, + 1,114,124,0,0,0,114,6,0,0,0,114,182,0,0,0, + 171,4,0,0,115,16,0,0,0,0,4,4,1,14,1,28, + 1,6,2,10,1,6,1,8,1,122,19,70,105,108,101,70, + 105,110,100,101,114,46,95,95,105,110,105,116,95,95,99,1, + 0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,67, + 0,0,0,115,10,0,0,0,100,3,124,0,95,0,100,2, + 83,0,41,4,122,31,73,110,118,97,108,105,100,97,116,101, + 32,116,104,101,32,100,105,114,101,99,116,111,114,121,32,109, + 116,105,109,101,46,114,31,0,0,0,78,114,91,0,0,0, + 41,1,114,7,1,0,0,41,1,114,104,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,249,0, + 0,0,185,4,0,0,115,2,0,0,0,0,2,122,28,70, + 105,108,101,70,105,110,100,101,114,46,105,110,118,97,108,105, + 100,97,116,101,95,99,97,99,104,101,115,99,2,0,0,0, + 0,0,0,0,3,0,0,0,2,0,0,0,67,0,0,0, + 115,42,0,0,0,124,0,106,0,124,1,131,1,125,2,124, + 2,100,1,107,8,114,26,100,1,103,0,102,2,83,0,124, + 2,106,1,124,2,106,2,112,38,103,0,102,2,83,0,41, + 2,122,197,84,114,121,32,116,111,32,102,105,110,100,32,97, + 32,108,111,97,100,101,114,32,102,111,114,32,116,104,101,32, + 115,112,101,99,105,102,105,101,100,32,109,111,100,117,108,101, + 44,32,111,114,32,116,104,101,32,110,97,109,101,115,112,97, + 99,101,10,32,32,32,32,32,32,32,32,112,97,99,107,97, + 103,101,32,112,111,114,116,105,111,110,115,46,32,82,101,116, + 117,114,110,115,32,40,108,111,97,100,101,114,44,32,108,105, + 115,116,45,111,102,45,112,111,114,116,105,111,110,115,41,46, + 10,10,32,32,32,32,32,32,32,32,84,104,105,115,32,109, + 101,116,104,111,100,32,105,115,32,100,101,112,114,101,99,97, + 116,101,100,46,32,32,85,115,101,32,102,105,110,100,95,115, + 112,101,99,40,41,32,105,110,115,116,101,97,100,46,10,10, + 32,32,32,32,32,32,32,32,78,41,3,114,178,0,0,0, + 114,124,0,0,0,114,154,0,0,0,41,3,114,104,0,0, + 0,114,123,0,0,0,114,162,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,121,0,0,0,191, + 4,0,0,115,8,0,0,0,0,7,10,1,8,1,8,1, + 122,22,70,105,108,101,70,105,110,100,101,114,46,102,105,110, + 100,95,108,111,97,100,101,114,99,6,0,0,0,0,0,0, + 0,7,0,0,0,6,0,0,0,67,0,0,0,115,26,0, + 0,0,124,1,124,2,124,3,131,2,125,6,116,0,124,2, + 124,3,124,6,124,4,100,1,141,4,83,0,41,2,78,41, + 2,114,124,0,0,0,114,154,0,0,0,41,1,114,165,0, + 0,0,41,7,114,104,0,0,0,114,163,0,0,0,114,123, + 0,0,0,114,37,0,0,0,90,4,115,109,115,108,114,177, + 0,0,0,114,124,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,4,1,0,0,203,4,0,0, + 115,6,0,0,0,0,1,10,1,8,1,122,20,70,105,108, + 101,70,105,110,100,101,114,46,95,103,101,116,95,115,112,101, + 99,78,99,3,0,0,0,0,0,0,0,14,0,0,0,15, + 0,0,0,67,0,0,0,115,98,1,0,0,100,1,125,3, + 124,1,106,0,100,2,131,1,100,3,25,0,125,4,121,24, + 116,1,124,0,106,2,112,34,116,3,106,4,131,0,131,1, + 106,5,125,5,87,0,110,24,4,0,116,6,107,10,114,66, + 1,0,1,0,1,0,100,10,125,5,89,0,110,2,88,0, + 124,5,124,0,106,7,107,3,114,92,124,0,106,8,131,0, + 1,0,124,5,124,0,95,7,116,9,131,0,114,114,124,0, + 106,10,125,6,124,4,106,11,131,0,125,7,110,10,124,0, + 106,12,125,6,124,4,125,7,124,7,124,6,107,6,114,218, + 116,13,124,0,106,2,124,4,131,2,125,8,120,72,124,0, + 106,14,68,0,93,54,92,2,125,9,125,10,100,5,124,9, + 23,0,125,11,116,13,124,8,124,11,131,2,125,12,116,15, + 124,12,131,1,114,152,124,0,106,16,124,10,124,1,124,12, + 124,8,103,1,124,2,131,5,83,0,113,152,87,0,116,17, + 124,8,131,1,125,3,120,88,124,0,106,14,68,0,93,78, + 92,2,125,9,125,10,116,13,124,0,106,2,124,4,124,9, + 23,0,131,2,125,12,116,18,106,19,100,6,124,12,100,3, + 100,7,141,3,1,0,124,7,124,9,23,0,124,6,107,6, + 114,226,116,15,124,12,131,1,114,226,124,0,106,16,124,10, + 124,1,124,12,100,8,124,2,131,5,83,0,113,226,87,0, + 124,3,144,1,114,94,116,18,106,19,100,9,124,8,131,2, + 1,0,116,18,106,20,124,1,100,8,131,2,125,13,124,8, + 103,1,124,13,95,21,124,13,83,0,100,8,83,0,41,11, + 122,111,84,114,121,32,116,111,32,102,105,110,100,32,97,32, + 115,112,101,99,32,102,111,114,32,116,104,101,32,115,112,101, + 99,105,102,105,101,100,32,109,111,100,117,108,101,46,10,10, + 32,32,32,32,32,32,32,32,82,101,116,117,114,110,115,32, + 116,104,101,32,109,97,116,99,104,105,110,103,32,115,112,101, + 99,44,32,111,114,32,78,111,110,101,32,105,102,32,110,111, + 116,32,102,111,117,110,100,46,10,32,32,32,32,32,32,32, + 32,70,114,61,0,0,0,114,59,0,0,0,114,31,0,0, + 0,114,182,0,0,0,122,9,116,114,121,105,110,103,32,123, + 125,41,1,90,9,118,101,114,98,111,115,105,116,121,78,122, + 25,112,111,115,115,105,98,108,101,32,110,97,109,101,115,112, + 97,99,101,32,102,111,114,32,123,125,114,91,0,0,0,41, + 22,114,34,0,0,0,114,41,0,0,0,114,37,0,0,0, + 114,3,0,0,0,114,47,0,0,0,114,216,0,0,0,114, + 42,0,0,0,114,7,1,0,0,218,11,95,102,105,108,108, + 95,99,97,99,104,101,114,7,0,0,0,114,10,1,0,0, + 114,92,0,0,0,114,9,1,0,0,114,30,0,0,0,114, + 6,1,0,0,114,46,0,0,0,114,4,1,0,0,114,48, + 0,0,0,114,118,0,0,0,114,133,0,0,0,114,158,0, + 0,0,114,154,0,0,0,41,14,114,104,0,0,0,114,123, + 0,0,0,114,177,0,0,0,90,12,105,115,95,110,97,109, + 101,115,112,97,99,101,90,11,116,97,105,108,95,109,111,100, + 117,108,101,114,130,0,0,0,90,5,99,97,99,104,101,90, + 12,99,97,99,104,101,95,109,111,100,117,108,101,90,9,98, + 97,115,101,95,112,97,116,104,114,222,0,0,0,114,163,0, + 0,0,90,13,105,110,105,116,95,102,105,108,101,110,97,109, + 101,90,9,102,117,108,108,95,112,97,116,104,114,162,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 114,178,0,0,0,208,4,0,0,115,70,0,0,0,0,5, + 4,1,14,1,2,1,24,1,14,1,10,1,10,1,8,1, + 6,2,6,1,6,1,10,2,6,1,4,2,8,1,12,1, + 16,1,8,1,10,1,8,1,24,4,8,2,16,1,16,1, + 16,1,12,1,8,1,10,1,12,1,6,1,12,1,12,1, + 8,1,4,1,122,20,70,105,108,101,70,105,110,100,101,114, + 46,102,105,110,100,95,115,112,101,99,99,1,0,0,0,0, + 0,0,0,9,0,0,0,13,0,0,0,67,0,0,0,115, + 194,0,0,0,124,0,106,0,125,1,121,22,116,1,106,2, + 124,1,112,22,116,1,106,3,131,0,131,1,125,2,87,0, + 110,30,4,0,116,4,116,5,116,6,102,3,107,10,114,58, + 1,0,1,0,1,0,103,0,125,2,89,0,110,2,88,0, + 116,7,106,8,106,9,100,1,131,1,115,84,116,10,124,2, + 131,1,124,0,95,11,110,78,116,10,131,0,125,3,120,64, + 124,2,68,0,93,56,125,4,124,4,106,12,100,2,131,1, + 92,3,125,5,125,6,125,7,124,6,114,138,100,3,106,13, + 124,5,124,7,106,14,131,0,131,2,125,8,110,4,124,5, + 125,8,124,3,106,15,124,8,131,1,1,0,113,96,87,0, + 124,3,124,0,95,11,116,7,106,8,106,9,116,16,131,1, + 114,190,100,4,100,5,132,0,124,2,68,0,131,1,124,0, + 95,17,100,6,83,0,41,7,122,68,70,105,108,108,32,116, + 104,101,32,99,97,99,104,101,32,111,102,32,112,111,116,101, + 110,116,105,97,108,32,109,111,100,117,108,101,115,32,97,110, + 100,32,112,97,99,107,97,103,101,115,32,102,111,114,32,116, + 104,105,115,32,100,105,114,101,99,116,111,114,121,46,114,0, + 0,0,0,114,61,0,0,0,122,5,123,125,46,123,125,99, + 1,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0, + 83,0,0,0,115,20,0,0,0,104,0,124,0,93,12,125, + 1,124,1,106,0,131,0,146,2,113,4,83,0,114,4,0, + 0,0,41,1,114,92,0,0,0,41,2,114,24,0,0,0, + 90,2,102,110,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,250,9,60,115,101,116,99,111,109,112,62,29,5, + 0,0,115,2,0,0,0,6,0,122,41,70,105,108,101,70, + 105,110,100,101,114,46,95,102,105,108,108,95,99,97,99,104, + 101,46,60,108,111,99,97,108,115,62,46,60,115,101,116,99, + 111,109,112,62,78,41,18,114,37,0,0,0,114,3,0,0, + 0,90,7,108,105,115,116,100,105,114,114,47,0,0,0,114, + 255,0,0,0,218,15,80,101,114,109,105,115,115,105,111,110, + 69,114,114,111,114,218,18,78,111,116,65,68,105,114,101,99, + 116,111,114,121,69,114,114,111,114,114,8,0,0,0,114,9, + 0,0,0,114,10,0,0,0,114,8,1,0,0,114,9,1, + 0,0,114,87,0,0,0,114,50,0,0,0,114,92,0,0, + 0,218,3,97,100,100,114,11,0,0,0,114,10,1,0,0, + 41,9,114,104,0,0,0,114,37,0,0,0,90,8,99,111, + 110,116,101,110,116,115,90,21,108,111,119,101,114,95,115,117, + 102,102,105,120,95,99,111,110,116,101,110,116,115,114,244,0, + 0,0,114,102,0,0,0,114,234,0,0,0,114,222,0,0, + 0,90,8,110,101,119,95,110,97,109,101,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,12,1,0,0,0, + 5,0,0,115,34,0,0,0,0,2,6,1,2,1,22,1, + 20,3,10,3,12,1,12,7,6,1,10,1,16,1,4,1, + 18,2,4,1,14,1,6,1,12,1,122,22,70,105,108,101, + 70,105,110,100,101,114,46,95,102,105,108,108,95,99,97,99, + 104,101,99,1,0,0,0,0,0,0,0,3,0,0,0,3, + 0,0,0,7,0,0,0,115,18,0,0,0,135,0,135,1, + 102,2,100,1,100,2,132,8,125,2,124,2,83,0,41,3, + 97,20,1,0,0,65,32,99,108,97,115,115,32,109,101,116, + 104,111,100,32,119,104,105,99,104,32,114,101,116,117,114,110, + 115,32,97,32,99,108,111,115,117,114,101,32,116,111,32,117, + 115,101,32,111,110,32,115,121,115,46,112,97,116,104,95,104, + 111,111,107,10,32,32,32,32,32,32,32,32,119,104,105,99, + 104,32,119,105,108,108,32,114,101,116,117,114,110,32,97,110, + 32,105,110,115,116,97,110,99,101,32,117,115,105,110,103,32, + 116,104,101,32,115,112,101,99,105,102,105,101,100,32,108,111, + 97,100,101,114,115,32,97,110,100,32,116,104,101,32,112,97, + 116,104,10,32,32,32,32,32,32,32,32,99,97,108,108,101, + 100,32,111,110,32,116,104,101,32,99,108,111,115,117,114,101, + 46,10,10,32,32,32,32,32,32,32,32,73,102,32,116,104, + 101,32,112,97,116,104,32,99,97,108,108,101,100,32,111,110, + 32,116,104,101,32,99,108,111,115,117,114,101,32,105,115,32, + 110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,44, + 32,73,109,112,111,114,116,69,114,114,111,114,32,105,115,10, + 32,32,32,32,32,32,32,32,114,97,105,115,101,100,46,10, + 10,32,32,32,32,32,32,32,32,99,1,0,0,0,0,0, + 0,0,1,0,0,0,4,0,0,0,19,0,0,0,115,34, + 0,0,0,116,0,124,0,131,1,115,20,116,1,100,1,124, + 0,100,2,141,2,130,1,136,0,124,0,102,1,136,1,158, + 2,142,0,83,0,41,3,122,45,80,97,116,104,32,104,111, + 111,107,32,102,111,114,32,105,109,112,111,114,116,108,105,98, + 46,109,97,99,104,105,110,101,114,121,46,70,105,108,101,70, + 105,110,100,101,114,46,122,30,111,110,108,121,32,100,105,114, + 101,99,116,111,114,105,101,115,32,97,114,101,32,115,117,112, + 112,111,114,116,101,100,41,1,114,37,0,0,0,41,2,114, + 48,0,0,0,114,103,0,0,0,41,1,114,37,0,0,0, + 41,2,114,168,0,0,0,114,11,1,0,0,114,4,0,0, + 0,114,6,0,0,0,218,24,112,97,116,104,95,104,111,111, + 107,95,102,111,114,95,70,105,108,101,70,105,110,100,101,114, + 41,5,0,0,115,6,0,0,0,0,2,8,1,12,1,122, + 54,70,105,108,101,70,105,110,100,101,114,46,112,97,116,104, + 95,104,111,111,107,46,60,108,111,99,97,108,115,62,46,112, + 97,116,104,95,104,111,111,107,95,102,111,114,95,70,105,108, + 101,70,105,110,100,101,114,114,4,0,0,0,41,3,114,168, + 0,0,0,114,11,1,0,0,114,17,1,0,0,114,4,0, + 0,0,41,2,114,168,0,0,0,114,11,1,0,0,114,6, + 0,0,0,218,9,112,97,116,104,95,104,111,111,107,31,5, + 0,0,115,4,0,0,0,0,10,14,6,122,20,70,105,108, + 101,70,105,110,100,101,114,46,112,97,116,104,95,104,111,111, + 107,99,1,0,0,0,0,0,0,0,1,0,0,0,2,0, + 0,0,67,0,0,0,115,12,0,0,0,100,1,106,0,124, + 0,106,1,131,1,83,0,41,2,78,122,16,70,105,108,101, + 70,105,110,100,101,114,40,123,33,114,125,41,41,2,114,50, + 0,0,0,114,37,0,0,0,41,1,114,104,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,114,243, + 0,0,0,49,5,0,0,115,2,0,0,0,0,1,122,19, + 70,105,108,101,70,105,110,100,101,114,46,95,95,114,101,112, + 114,95,95,41,1,78,41,15,114,109,0,0,0,114,108,0, + 0,0,114,110,0,0,0,114,111,0,0,0,114,182,0,0, + 0,114,249,0,0,0,114,127,0,0,0,114,179,0,0,0, + 114,121,0,0,0,114,4,1,0,0,114,178,0,0,0,114, + 12,1,0,0,114,180,0,0,0,114,18,1,0,0,114,243, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,5,1,0,0,162,4,0,0, + 115,20,0,0,0,8,7,4,2,8,14,8,4,4,2,8, + 12,8,5,10,48,8,31,12,18,114,5,1,0,0,99,4, + 0,0,0,0,0,0,0,6,0,0,0,11,0,0,0,67, + 0,0,0,115,146,0,0,0,124,0,106,0,100,1,131,1, + 125,4,124,0,106,0,100,2,131,1,125,5,124,4,115,66, + 124,5,114,36,124,5,106,1,125,4,110,30,124,2,124,3, + 107,2,114,56,116,2,124,1,124,2,131,2,125,4,110,10, + 116,3,124,1,124,2,131,2,125,4,124,5,115,84,116,4, + 124,1,124,2,124,4,100,3,141,3,125,5,121,36,124,5, + 124,0,100,2,60,0,124,4,124,0,100,1,60,0,124,2, + 124,0,100,4,60,0,124,3,124,0,100,5,60,0,87,0, + 110,20,4,0,116,5,107,10,114,140,1,0,1,0,1,0, + 89,0,110,2,88,0,100,0,83,0,41,6,78,218,10,95, + 95,108,111,97,100,101,114,95,95,218,8,95,95,115,112,101, + 99,95,95,41,1,114,124,0,0,0,90,8,95,95,102,105, + 108,101,95,95,90,10,95,95,99,97,99,104,101,100,95,95, + 41,6,218,3,103,101,116,114,124,0,0,0,114,220,0,0, + 0,114,215,0,0,0,114,165,0,0,0,218,9,69,120,99, + 101,112,116,105,111,110,41,6,90,2,110,115,114,102,0,0, + 0,90,8,112,97,116,104,110,97,109,101,90,9,99,112,97, + 116,104,110,97,109,101,114,124,0,0,0,114,162,0,0,0, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, + 14,95,102,105,120,95,117,112,95,109,111,100,117,108,101,55, + 5,0,0,115,34,0,0,0,0,2,10,1,10,1,4,1, + 4,1,8,1,8,1,12,2,10,1,4,1,14,1,2,1, + 8,1,8,1,8,1,12,1,14,2,114,23,1,0,0,99, + 0,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0, + 67,0,0,0,115,38,0,0,0,116,0,116,1,106,2,131, + 0,102,2,125,0,116,3,116,4,102,2,125,1,116,5,116, + 6,102,2,125,2,124,0,124,1,124,2,103,3,83,0,41, + 1,122,95,82,101,116,117,114,110,115,32,97,32,108,105,115, + 116,32,111,102,32,102,105,108,101,45,98,97,115,101,100,32, + 109,111,100,117,108,101,32,108,111,97,100,101,114,115,46,10, + 10,32,32,32,32,69,97,99,104,32,105,116,101,109,32,105, + 115,32,97,32,116,117,112,108,101,32,40,108,111,97,100,101, + 114,44,32,115,117,102,102,105,120,101,115,41,46,10,32,32, + 32,32,41,7,114,221,0,0,0,114,143,0,0,0,218,18, + 101,120,116,101,110,115,105,111,110,95,115,117,102,102,105,120, + 101,115,114,215,0,0,0,114,88,0,0,0,114,220,0,0, + 0,114,78,0,0,0,41,3,90,10,101,120,116,101,110,115, + 105,111,110,115,90,6,115,111,117,114,99,101,90,8,98,121, + 116,101,99,111,100,101,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,114,159,0,0,0,78,5,0,0,115,8, + 0,0,0,0,5,12,1,8,1,8,1,114,159,0,0,0, + 99,1,0,0,0,0,0,0,0,12,0,0,0,12,0,0, + 0,67,0,0,0,115,188,1,0,0,124,0,97,0,116,0, + 106,1,97,1,116,0,106,2,97,2,116,1,106,3,116,4, + 25,0,125,1,120,56,100,26,68,0,93,48,125,2,124,2, + 116,1,106,3,107,7,114,58,116,0,106,5,124,2,131,1, + 125,3,110,10,116,1,106,3,124,2,25,0,125,3,116,6, + 124,1,124,2,124,3,131,3,1,0,113,32,87,0,100,5, + 100,6,103,1,102,2,100,7,100,8,100,6,103,2,102,2, + 102,2,125,4,120,118,124,4,68,0,93,102,92,2,125,5, + 125,6,116,7,100,9,100,10,132,0,124,6,68,0,131,1, + 131,1,115,142,116,8,130,1,124,6,100,11,25,0,125,7, + 124,5,116,1,106,3,107,6,114,174,116,1,106,3,124,5, + 25,0,125,8,80,0,113,112,121,16,116,0,106,5,124,5, + 131,1,125,8,80,0,87,0,113,112,4,0,116,9,107,10, + 114,212,1,0,1,0,1,0,119,112,89,0,113,112,88,0, + 113,112,87,0,116,9,100,12,131,1,130,1,116,6,124,1, + 100,13,124,8,131,3,1,0,116,6,124,1,100,14,124,7, + 131,3,1,0,116,6,124,1,100,15,100,16,106,10,124,6, + 131,1,131,3,1,0,121,14,116,0,106,5,100,17,131,1, + 125,9,87,0,110,26,4,0,116,9,107,10,144,1,114,52, + 1,0,1,0,1,0,100,18,125,9,89,0,110,2,88,0, + 116,6,124,1,100,17,124,9,131,3,1,0,116,0,106,5, + 100,19,131,1,125,10,116,6,124,1,100,19,124,10,131,3, + 1,0,124,5,100,7,107,2,144,1,114,120,116,0,106,5, + 100,20,131,1,125,11,116,6,124,1,100,21,124,11,131,3, + 1,0,116,6,124,1,100,22,116,11,131,0,131,3,1,0, + 116,12,106,13,116,2,106,14,131,0,131,1,1,0,124,5, + 100,7,107,2,144,1,114,184,116,15,106,16,100,23,131,1, + 1,0,100,24,116,12,107,6,144,1,114,184,100,25,116,17, + 95,18,100,18,83,0,41,27,122,205,83,101,116,117,112,32, + 116,104,101,32,112,97,116,104,45,98,97,115,101,100,32,105, + 109,112,111,114,116,101,114,115,32,102,111,114,32,105,109,112, + 111,114,116,108,105,98,32,98,121,32,105,109,112,111,114,116, + 105,110,103,32,110,101,101,100,101,100,10,32,32,32,32,98, + 117,105,108,116,45,105,110,32,109,111,100,117,108,101,115,32, + 97,110,100,32,105,110,106,101,99,116,105,110,103,32,116,104, + 101,109,32,105,110,116,111,32,116,104,101,32,103,108,111,98, + 97,108,32,110,97,109,101,115,112,97,99,101,46,10,10,32, + 32,32,32,79,116,104,101,114,32,99,111,109,112,111,110,101, + 110,116,115,32,97,114,101,32,101,120,116,114,97,99,116,101, + 100,32,102,114,111,109,32,116,104,101,32,99,111,114,101,32, + 98,111,111,116,115,116,114,97,112,32,109,111,100,117,108,101, + 46,10,10,32,32,32,32,114,52,0,0,0,114,63,0,0, + 0,218,8,98,117,105,108,116,105,110,115,114,140,0,0,0, + 90,5,112,111,115,105,120,250,1,47,218,2,110,116,250,1, + 92,99,1,0,0,0,0,0,0,0,2,0,0,0,3,0, + 0,0,115,0,0,0,115,26,0,0,0,124,0,93,18,125, + 1,116,0,124,1,131,1,100,0,107,2,86,0,1,0,113, + 2,100,1,83,0,41,2,114,31,0,0,0,78,41,1,114, + 33,0,0,0,41,2,114,24,0,0,0,114,81,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 159,0,0,0,78,5,0,0,115,8,0,0,0,0,5,12, - 1,8,1,8,1,114,159,0,0,0,99,1,0,0,0,0, - 0,0,0,12,0,0,0,12,0,0,0,67,0,0,0,115, - 188,1,0,0,124,0,97,0,116,0,106,1,97,1,116,0, - 106,2,97,2,116,1,106,3,116,4,25,0,125,1,120,56, - 100,26,68,0,93,48,125,2,124,2,116,1,106,3,107,7, - 114,58,116,0,106,5,124,2,131,1,125,3,110,10,116,1, - 106,3,124,2,25,0,125,3,116,6,124,1,124,2,124,3, - 131,3,1,0,113,32,87,0,100,5,100,6,103,1,102,2, - 100,7,100,8,100,6,103,2,102,2,102,2,125,4,120,118, - 124,4,68,0,93,102,92,2,125,5,125,6,116,7,100,9, - 100,10,132,0,124,6,68,0,131,1,131,1,115,142,116,8, - 130,1,124,6,100,11,25,0,125,7,124,5,116,1,106,3, - 107,6,114,174,116,1,106,3,124,5,25,0,125,8,80,0, - 113,112,121,16,116,0,106,5,124,5,131,1,125,8,80,0, - 87,0,113,112,4,0,116,9,107,10,114,212,1,0,1,0, - 1,0,119,112,89,0,113,112,88,0,113,112,87,0,116,9, - 100,12,131,1,130,1,116,6,124,1,100,13,124,8,131,3, - 1,0,116,6,124,1,100,14,124,7,131,3,1,0,116,6, - 124,1,100,15,100,16,106,10,124,6,131,1,131,3,1,0, - 121,14,116,0,106,5,100,17,131,1,125,9,87,0,110,26, - 4,0,116,9,107,10,144,1,114,52,1,0,1,0,1,0, - 100,18,125,9,89,0,110,2,88,0,116,6,124,1,100,17, - 124,9,131,3,1,0,116,0,106,5,100,19,131,1,125,10, - 116,6,124,1,100,19,124,10,131,3,1,0,124,5,100,7, - 107,2,144,1,114,120,116,0,106,5,100,20,131,1,125,11, - 116,6,124,1,100,21,124,11,131,3,1,0,116,6,124,1, - 100,22,116,11,131,0,131,3,1,0,116,12,106,13,116,2, - 106,14,131,0,131,1,1,0,124,5,100,7,107,2,144,1, - 114,184,116,15,106,16,100,23,131,1,1,0,100,24,116,12, - 107,6,144,1,114,184,100,25,116,17,95,18,100,18,83,0, - 41,27,122,205,83,101,116,117,112,32,116,104,101,32,112,97, - 116,104,45,98,97,115,101,100,32,105,109,112,111,114,116,101, - 114,115,32,102,111,114,32,105,109,112,111,114,116,108,105,98, - 32,98,121,32,105,109,112,111,114,116,105,110,103,32,110,101, - 101,100,101,100,10,32,32,32,32,98,117,105,108,116,45,105, - 110,32,109,111,100,117,108,101,115,32,97,110,100,32,105,110, - 106,101,99,116,105,110,103,32,116,104,101,109,32,105,110,116, - 111,32,116,104,101,32,103,108,111,98,97,108,32,110,97,109, - 101,115,112,97,99,101,46,10,10,32,32,32,32,79,116,104, - 101,114,32,99,111,109,112,111,110,101,110,116,115,32,97,114, - 101,32,101,120,116,114,97,99,116,101,100,32,102,114,111,109, - 32,116,104,101,32,99,111,114,101,32,98,111,111,116,115,116, - 114,97,112,32,109,111,100,117,108,101,46,10,10,32,32,32, - 32,114,52,0,0,0,114,63,0,0,0,218,8,98,117,105, - 108,116,105,110,115,114,140,0,0,0,90,5,112,111,115,105, - 120,250,1,47,218,2,110,116,250,1,92,99,1,0,0,0, - 0,0,0,0,2,0,0,0,3,0,0,0,115,0,0,0, - 115,26,0,0,0,124,0,93,18,125,1,116,0,124,1,131, - 1,100,0,107,2,86,0,1,0,113,2,100,1,83,0,41, - 2,114,31,0,0,0,78,41,1,114,33,0,0,0,41,2, - 114,24,0,0,0,114,81,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,224,0,0,0,114,5, - 0,0,115,2,0,0,0,4,0,122,25,95,115,101,116,117, - 112,46,60,108,111,99,97,108,115,62,46,60,103,101,110,101, - 120,112,114,62,114,62,0,0,0,122,30,105,109,112,111,114, - 116,108,105,98,32,114,101,113,117,105,114,101,115,32,112,111, - 115,105,120,32,111,114,32,110,116,114,3,0,0,0,114,27, - 0,0,0,114,23,0,0,0,114,32,0,0,0,90,7,95, - 116,104,114,101,97,100,78,90,8,95,119,101,97,107,114,101, - 102,90,6,119,105,110,114,101,103,114,167,0,0,0,114,7, - 0,0,0,122,4,46,112,121,119,122,6,95,100,46,112,121, - 100,84,41,4,114,52,0,0,0,114,63,0,0,0,114,25, - 1,0,0,114,140,0,0,0,41,19,114,118,0,0,0,114, - 8,0,0,0,114,143,0,0,0,114,236,0,0,0,114,109, - 0,0,0,90,18,95,98,117,105,108,116,105,110,95,102,114, - 111,109,95,110,97,109,101,114,113,0,0,0,218,3,97,108, - 108,218,14,65,115,115,101,114,116,105,111,110,69,114,114,111, - 114,114,103,0,0,0,114,28,0,0,0,114,13,0,0,0, - 114,226,0,0,0,114,147,0,0,0,114,24,1,0,0,114, - 88,0,0,0,114,161,0,0,0,114,166,0,0,0,114,170, - 0,0,0,41,12,218,17,95,98,111,111,116,115,116,114,97, - 112,95,109,111,100,117,108,101,90,11,115,101,108,102,95,109, - 111,100,117,108,101,90,12,98,117,105,108,116,105,110,95,110, - 97,109,101,90,14,98,117,105,108,116,105,110,95,109,111,100, - 117,108,101,90,10,111,115,95,100,101,116,97,105,108,115,90, - 10,98,117,105,108,116,105,110,95,111,115,114,23,0,0,0, - 114,27,0,0,0,90,9,111,115,95,109,111,100,117,108,101, - 90,13,116,104,114,101,97,100,95,109,111,100,117,108,101,90, - 14,119,101,97,107,114,101,102,95,109,111,100,117,108,101,90, - 13,119,105,110,114,101,103,95,109,111,100,117,108,101,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,218,6,95, - 115,101,116,117,112,89,5,0,0,115,82,0,0,0,0,8, - 4,1,6,1,6,3,10,1,10,1,10,1,12,2,10,1, - 16,3,22,1,14,2,22,1,8,1,10,1,10,1,4,2, - 2,1,10,1,6,1,14,1,12,2,8,1,12,1,12,1, - 18,3,2,1,14,1,16,2,10,1,12,3,10,1,12,3, - 10,1,10,1,12,3,14,1,14,1,10,1,10,1,10,1, - 114,32,1,0,0,99,1,0,0,0,0,0,0,0,2,0, - 0,0,3,0,0,0,67,0,0,0,115,72,0,0,0,116, - 0,124,0,131,1,1,0,116,1,131,0,125,1,116,2,106, - 3,106,4,116,5,106,6,124,1,142,0,103,1,131,1,1, - 0,116,7,106,8,100,1,107,2,114,56,116,2,106,9,106, - 10,116,11,131,1,1,0,116,2,106,9,106,10,116,12,131, - 1,1,0,100,2,83,0,41,3,122,41,73,110,115,116,97, - 108,108,32,116,104,101,32,112,97,116,104,45,98,97,115,101, - 100,32,105,109,112,111,114,116,32,99,111,109,112,111,110,101, - 110,116,115,46,114,27,1,0,0,78,41,13,114,32,1,0, - 0,114,159,0,0,0,114,8,0,0,0,114,253,0,0,0, - 114,147,0,0,0,114,5,1,0,0,114,18,1,0,0,114, - 3,0,0,0,114,109,0,0,0,218,9,109,101,116,97,95, - 112,97,116,104,114,161,0,0,0,114,166,0,0,0,114,248, - 0,0,0,41,2,114,31,1,0,0,90,17,115,117,112,112, - 111,114,116,101,100,95,108,111,97,100,101,114,115,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,8,95,105, - 110,115,116,97,108,108,157,5,0,0,115,12,0,0,0,0, - 2,8,1,6,1,20,1,10,1,12,1,114,34,1,0,0, - 41,1,114,0,0,0,0,41,2,114,1,0,0,0,114,2, - 0,0,0,41,1,114,49,0,0,0,41,1,78,41,3,78, - 78,78,41,3,78,78,78,41,2,114,62,0,0,0,114,62, - 0,0,0,41,1,78,41,1,78,41,58,114,111,0,0,0, - 114,12,0,0,0,90,37,95,67,65,83,69,95,73,78,83, - 69,78,83,73,84,73,86,69,95,80,76,65,84,70,79,82, - 77,83,95,66,89,84,69,83,95,75,69,89,114,11,0,0, - 0,114,13,0,0,0,114,19,0,0,0,114,21,0,0,0, - 114,30,0,0,0,114,40,0,0,0,114,41,0,0,0,114, - 45,0,0,0,114,46,0,0,0,114,48,0,0,0,114,58, - 0,0,0,218,4,116,121,112,101,218,8,95,95,99,111,100, - 101,95,95,114,142,0,0,0,114,17,0,0,0,114,132,0, - 0,0,114,16,0,0,0,114,20,0,0,0,90,17,95,82, - 65,87,95,77,65,71,73,67,95,78,85,77,66,69,82,114, - 77,0,0,0,114,76,0,0,0,114,88,0,0,0,114,78, - 0,0,0,90,23,68,69,66,85,71,95,66,89,84,69,67, - 79,68,69,95,83,85,70,70,73,88,69,83,90,27,79,80, - 84,73,77,73,90,69,68,95,66,89,84,69,67,79,68,69, - 95,83,85,70,70,73,88,69,83,114,83,0,0,0,114,89, - 0,0,0,114,95,0,0,0,114,99,0,0,0,114,101,0, - 0,0,114,120,0,0,0,114,127,0,0,0,114,139,0,0, - 0,114,145,0,0,0,114,148,0,0,0,114,153,0,0,0, - 218,6,111,98,106,101,99,116,114,160,0,0,0,114,165,0, - 0,0,114,166,0,0,0,114,181,0,0,0,114,191,0,0, - 0,114,207,0,0,0,114,215,0,0,0,114,220,0,0,0, - 114,226,0,0,0,114,221,0,0,0,114,227,0,0,0,114, - 246,0,0,0,114,248,0,0,0,114,5,1,0,0,114,23, - 1,0,0,114,159,0,0,0,114,32,1,0,0,114,34,1, - 0,0,114,4,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,8,60,109,111,100,117,108,101,62, - 8,0,0,0,115,108,0,0,0,4,16,4,1,4,1,2, - 1,6,3,8,17,8,5,8,5,8,6,8,12,8,10,8, - 9,8,5,8,7,10,22,10,122,16,1,12,2,4,1,4, - 2,6,2,6,2,8,2,16,45,8,34,8,19,8,12,8, - 12,8,28,8,17,10,55,10,12,10,10,8,14,6,3,4, - 1,14,67,14,64,14,29,16,110,14,41,18,45,18,16,4, - 3,18,53,14,60,14,42,14,127,0,5,14,127,0,22,10, - 23,8,11,8,68, + 224,0,0,0,114,5,0,0,115,2,0,0,0,4,0,122, + 25,95,115,101,116,117,112,46,60,108,111,99,97,108,115,62, + 46,60,103,101,110,101,120,112,114,62,114,62,0,0,0,122, + 30,105,109,112,111,114,116,108,105,98,32,114,101,113,117,105, + 114,101,115,32,112,111,115,105,120,32,111,114,32,110,116,114, + 3,0,0,0,114,27,0,0,0,114,23,0,0,0,114,32, + 0,0,0,90,7,95,116,104,114,101,97,100,78,90,8,95, + 119,101,97,107,114,101,102,90,6,119,105,110,114,101,103,114, + 167,0,0,0,114,7,0,0,0,122,4,46,112,121,119,122, + 6,95,100,46,112,121,100,84,41,4,114,52,0,0,0,114, + 63,0,0,0,114,25,1,0,0,114,140,0,0,0,41,19, + 114,118,0,0,0,114,8,0,0,0,114,143,0,0,0,114, + 236,0,0,0,114,109,0,0,0,90,18,95,98,117,105,108, + 116,105,110,95,102,114,111,109,95,110,97,109,101,114,113,0, + 0,0,218,3,97,108,108,218,14,65,115,115,101,114,116,105, + 111,110,69,114,114,111,114,114,103,0,0,0,114,28,0,0, + 0,114,13,0,0,0,114,226,0,0,0,114,147,0,0,0, + 114,24,1,0,0,114,88,0,0,0,114,161,0,0,0,114, + 166,0,0,0,114,170,0,0,0,41,12,218,17,95,98,111, + 111,116,115,116,114,97,112,95,109,111,100,117,108,101,90,11, + 115,101,108,102,95,109,111,100,117,108,101,90,12,98,117,105, + 108,116,105,110,95,110,97,109,101,90,14,98,117,105,108,116, + 105,110,95,109,111,100,117,108,101,90,10,111,115,95,100,101, + 116,97,105,108,115,90,10,98,117,105,108,116,105,110,95,111, + 115,114,23,0,0,0,114,27,0,0,0,90,9,111,115,95, + 109,111,100,117,108,101,90,13,116,104,114,101,97,100,95,109, + 111,100,117,108,101,90,14,119,101,97,107,114,101,102,95,109, + 111,100,117,108,101,90,13,119,105,110,114,101,103,95,109,111, + 100,117,108,101,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,218,6,95,115,101,116,117,112,89,5,0,0,115, + 82,0,0,0,0,8,4,1,6,1,6,3,10,1,10,1, + 10,1,12,2,10,1,16,3,22,1,14,2,22,1,8,1, + 10,1,10,1,4,2,2,1,10,1,6,1,14,1,12,2, + 8,1,12,1,12,1,18,3,2,1,14,1,16,2,10,1, + 12,3,10,1,12,3,10,1,10,1,12,3,14,1,14,1, + 10,1,10,1,10,1,114,32,1,0,0,99,1,0,0,0, + 0,0,0,0,2,0,0,0,3,0,0,0,67,0,0,0, + 115,72,0,0,0,116,0,124,0,131,1,1,0,116,1,131, + 0,125,1,116,2,106,3,106,4,116,5,106,6,124,1,142, + 0,103,1,131,1,1,0,116,7,106,8,100,1,107,2,114, + 56,116,2,106,9,106,10,116,11,131,1,1,0,116,2,106, + 9,106,10,116,12,131,1,1,0,100,2,83,0,41,3,122, + 41,73,110,115,116,97,108,108,32,116,104,101,32,112,97,116, + 104,45,98,97,115,101,100,32,105,109,112,111,114,116,32,99, + 111,109,112,111,110,101,110,116,115,46,114,27,1,0,0,78, + 41,13,114,32,1,0,0,114,159,0,0,0,114,8,0,0, + 0,114,253,0,0,0,114,147,0,0,0,114,5,1,0,0, + 114,18,1,0,0,114,3,0,0,0,114,109,0,0,0,218, + 9,109,101,116,97,95,112,97,116,104,114,161,0,0,0,114, + 166,0,0,0,114,248,0,0,0,41,2,114,31,1,0,0, + 90,17,115,117,112,112,111,114,116,101,100,95,108,111,97,100, + 101,114,115,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,218,8,95,105,110,115,116,97,108,108,157,5,0,0, + 115,12,0,0,0,0,2,8,1,6,1,20,1,10,1,12, + 1,114,34,1,0,0,41,1,114,0,0,0,0,41,2,114, + 1,0,0,0,114,2,0,0,0,41,1,114,49,0,0,0, + 41,1,78,41,3,78,78,78,41,3,78,78,78,41,2,114, + 62,0,0,0,114,62,0,0,0,41,1,78,41,1,78,41, + 58,114,111,0,0,0,114,12,0,0,0,90,37,95,67,65, + 83,69,95,73,78,83,69,78,83,73,84,73,86,69,95,80, + 76,65,84,70,79,82,77,83,95,66,89,84,69,83,95,75, + 69,89,114,11,0,0,0,114,13,0,0,0,114,19,0,0, + 0,114,21,0,0,0,114,30,0,0,0,114,40,0,0,0, + 114,41,0,0,0,114,45,0,0,0,114,46,0,0,0,114, + 48,0,0,0,114,58,0,0,0,218,4,116,121,112,101,218, + 8,95,95,99,111,100,101,95,95,114,142,0,0,0,114,17, + 0,0,0,114,132,0,0,0,114,16,0,0,0,114,20,0, + 0,0,90,17,95,82,65,87,95,77,65,71,73,67,95,78, + 85,77,66,69,82,114,77,0,0,0,114,76,0,0,0,114, + 88,0,0,0,114,78,0,0,0,90,23,68,69,66,85,71, + 95,66,89,84,69,67,79,68,69,95,83,85,70,70,73,88, + 69,83,90,27,79,80,84,73,77,73,90,69,68,95,66,89, + 84,69,67,79,68,69,95,83,85,70,70,73,88,69,83,114, + 83,0,0,0,114,89,0,0,0,114,95,0,0,0,114,99, + 0,0,0,114,101,0,0,0,114,120,0,0,0,114,127,0, + 0,0,114,139,0,0,0,114,145,0,0,0,114,148,0,0, + 0,114,153,0,0,0,218,6,111,98,106,101,99,116,114,160, + 0,0,0,114,165,0,0,0,114,166,0,0,0,114,181,0, + 0,0,114,191,0,0,0,114,207,0,0,0,114,215,0,0, + 0,114,220,0,0,0,114,226,0,0,0,114,221,0,0,0, + 114,227,0,0,0,114,246,0,0,0,114,248,0,0,0,114, + 5,1,0,0,114,23,1,0,0,114,159,0,0,0,114,32, + 1,0,0,114,34,1,0,0,114,4,0,0,0,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,218,8,60,109, + 111,100,117,108,101,62,8,0,0,0,115,108,0,0,0,4, + 16,4,1,4,1,2,1,6,3,8,17,8,5,8,5,8, + 6,8,12,8,10,8,9,8,5,8,7,10,22,10,122,16, + 1,12,2,4,1,4,2,6,2,6,2,8,2,16,45,8, + 34,8,19,8,12,8,12,8,28,8,17,10,55,10,12,10, + 10,8,14,6,3,4,1,14,67,14,64,14,29,16,110,14, + 41,18,45,18,16,4,3,18,53,14,60,14,42,14,127,0, + 5,14,127,0,22,10,23,8,11,8,68, }; diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -704,11 +704,11 @@ /* Remove unreachable ops after RETURN */ case RETURN_VALUE: h = i + 1; - while (h + 1 < codelen && ISBASICBLOCK(blocks, i, h + 1)) { + while (h < codelen && ISBASICBLOCK(blocks, i, h)) { h++; } if (h > i + 1) { - fill_nops(codestr, i + 1, h + 1); + fill_nops(codestr, i + 1, h); nexti = find_op(codestr, h); } break; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:42:29 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 06:42:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328517=3A_Fixed_of-by-one_error_in_the_peephole_?= =?utf-8?q?optimizer_that_caused?= Message-ID: <20161025064229.110755.96422.6CFD32E6@psf.io> https://hg.python.org/cpython/rev/8d571fab4d66 changeset: 104687:8d571fab4d66 parent: 104685:ffaf02ec9d8b parent: 104686:5784cc37b5f4 user: Serhiy Storchaka date: Tue Oct 25 09:32:04 2016 +0300 summary: Issue #28517: Fixed of-by-one error in the peephole optimizer that caused keeping unreachable code. files: Misc/NEWS | 3 + Python/importlib.h | 2298 ++++++------ Python/importlib_external.h | 3917 +++++++++++----------- Python/peephole.c | 4 +- 4 files changed, 3111 insertions(+), 3111 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28517: Fixed of-by-one error in the peephole optimizer that caused + keeping unreachable code. + - Issue #28214: Improved exception reporting for problematic __set_name__ attributes. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/importlib_external.h b/Python/importlib_external.h --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -459,1979 +459,1978 @@ 101,85,1,0,0,115,20,0,0,0,0,7,12,1,4,1, 16,1,26,1,4,1,2,1,12,1,18,1,18,1,114,95, 0,0,0,99,1,0,0,0,0,0,0,0,1,0,0,0, - 11,0,0,0,67,0,0,0,115,74,0,0,0,124,0,106, + 11,0,0,0,67,0,0,0,115,72,0,0,0,124,0,106, 0,116,1,116,2,131,1,131,1,114,46,121,8,116,3,124, 0,131,1,83,0,4,0,116,4,107,10,114,42,1,0,1, - 0,1,0,89,0,113,70,88,0,110,24,124,0,106,0,116, - 1,116,5,131,1,131,1,114,66,124,0,83,0,110,4,100, - 0,83,0,100,0,83,0,41,1,78,41,6,218,8,101,110, - 100,115,119,105,116,104,218,5,116,117,112,108,101,114,88,0, - 0,0,114,83,0,0,0,114,70,0,0,0,114,78,0,0, - 0,41,1,218,8,102,105,108,101,110,97,109,101,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,11,95,103, - 101,116,95,99,97,99,104,101,100,104,1,0,0,115,16,0, - 0,0,0,1,14,1,2,1,8,1,14,1,8,1,14,1, - 6,2,114,99,0,0,0,99,1,0,0,0,0,0,0,0, - 2,0,0,0,11,0,0,0,67,0,0,0,115,52,0,0, - 0,121,14,116,0,124,0,131,1,106,1,125,1,87,0,110, - 24,4,0,116,2,107,10,114,38,1,0,1,0,1,0,100, - 1,125,1,89,0,110,2,88,0,124,1,100,2,79,0,125, - 1,124,1,83,0,41,3,122,51,67,97,108,99,117,108,97, - 116,101,32,116,104,101,32,109,111,100,101,32,112,101,114,109, - 105,115,115,105,111,110,115,32,102,111,114,32,97,32,98,121, - 116,101,99,111,100,101,32,102,105,108,101,46,105,182,1,0, - 0,233,128,0,0,0,41,3,114,41,0,0,0,114,43,0, - 0,0,114,42,0,0,0,41,2,114,37,0,0,0,114,44, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,10,95,99,97,108,99,95,109,111,100,101,116,1, - 0,0,115,12,0,0,0,0,2,2,1,14,1,14,1,10, - 3,8,1,114,101,0,0,0,99,1,0,0,0,0,0,0, - 0,3,0,0,0,11,0,0,0,3,0,0,0,115,68,0, - 0,0,100,6,135,0,102,1,100,2,100,3,132,9,125,1, - 121,10,116,0,106,1,125,2,87,0,110,28,4,0,116,2, - 107,10,114,52,1,0,1,0,1,0,100,4,100,5,132,0, - 125,2,89,0,110,2,88,0,124,2,124,1,136,0,131,2, - 1,0,124,1,83,0,41,7,122,252,68,101,99,111,114,97, - 116,111,114,32,116,111,32,118,101,114,105,102,121,32,116,104, - 97,116,32,116,104,101,32,109,111,100,117,108,101,32,98,101, - 105,110,103,32,114,101,113,117,101,115,116,101,100,32,109,97, - 116,99,104,101,115,32,116,104,101,32,111,110,101,32,116,104, - 101,10,32,32,32,32,108,111,97,100,101,114,32,99,97,110, - 32,104,97,110,100,108,101,46,10,10,32,32,32,32,84,104, - 101,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116, - 32,40,115,101,108,102,41,32,109,117,115,116,32,100,101,102, - 105,110,101,32,95,110,97,109,101,32,119,104,105,99,104,32, - 116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109, - 101,110,116,32,105,115,10,32,32,32,32,99,111,109,112,97, - 114,101,100,32,97,103,97,105,110,115,116,46,32,73,102,32, - 116,104,101,32,99,111,109,112,97,114,105,115,111,110,32,102, - 97,105,108,115,32,116,104,101,110,32,73,109,112,111,114,116, - 69,114,114,111,114,32,105,115,32,114,97,105,115,101,100,46, - 10,10,32,32,32,32,78,99,2,0,0,0,0,0,0,0, - 4,0,0,0,4,0,0,0,31,0,0,0,115,66,0,0, - 0,124,1,100,0,107,8,114,16,124,0,106,0,125,1,110, - 32,124,0,106,0,124,1,107,3,114,48,116,1,100,1,124, - 0,106,0,124,1,102,2,22,0,124,1,100,2,141,2,130, - 1,136,0,124,0,124,1,102,2,124,2,158,2,124,3,142, - 1,83,0,41,3,78,122,30,108,111,97,100,101,114,32,102, - 111,114,32,37,115,32,99,97,110,110,111,116,32,104,97,110, - 100,108,101,32,37,115,41,1,218,4,110,97,109,101,41,2, - 114,102,0,0,0,218,11,73,109,112,111,114,116,69,114,114, - 111,114,41,4,218,4,115,101,108,102,114,102,0,0,0,218, - 4,97,114,103,115,90,6,107,119,97,114,103,115,41,1,218, - 6,109,101,116,104,111,100,114,4,0,0,0,114,6,0,0, - 0,218,19,95,99,104,101,99,107,95,110,97,109,101,95,119, - 114,97,112,112,101,114,136,1,0,0,115,12,0,0,0,0, - 1,8,1,8,1,10,1,4,1,18,1,122,40,95,99,104, - 101,99,107,95,110,97,109,101,46,60,108,111,99,97,108,115, - 62,46,95,99,104,101,99,107,95,110,97,109,101,95,119,114, - 97,112,112,101,114,99,2,0,0,0,0,0,0,0,3,0, - 0,0,7,0,0,0,83,0,0,0,115,60,0,0,0,120, - 40,100,5,68,0,93,32,125,2,116,0,124,1,124,2,131, - 2,114,6,116,1,124,0,124,2,116,2,124,1,124,2,131, - 2,131,3,1,0,113,6,87,0,124,0,106,3,106,4,124, - 1,106,3,131,1,1,0,100,0,83,0,41,6,78,218,10, - 95,95,109,111,100,117,108,101,95,95,218,8,95,95,110,97, - 109,101,95,95,218,12,95,95,113,117,97,108,110,97,109,101, - 95,95,218,7,95,95,100,111,99,95,95,41,4,114,108,0, - 0,0,114,109,0,0,0,114,110,0,0,0,114,111,0,0, - 0,41,5,218,7,104,97,115,97,116,116,114,218,7,115,101, - 116,97,116,116,114,218,7,103,101,116,97,116,116,114,218,8, - 95,95,100,105,99,116,95,95,218,6,117,112,100,97,116,101, - 41,3,90,3,110,101,119,90,3,111,108,100,114,55,0,0, + 0,1,0,89,0,113,68,88,0,110,22,124,0,106,0,116, + 1,116,5,131,1,131,1,114,64,124,0,83,0,100,0,83, + 0,100,0,83,0,41,1,78,41,6,218,8,101,110,100,115, + 119,105,116,104,218,5,116,117,112,108,101,114,88,0,0,0, + 114,83,0,0,0,114,70,0,0,0,114,78,0,0,0,41, + 1,218,8,102,105,108,101,110,97,109,101,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,11,95,103,101,116, + 95,99,97,99,104,101,100,104,1,0,0,115,16,0,0,0, + 0,1,14,1,2,1,8,1,14,1,8,1,14,1,4,2, + 114,99,0,0,0,99,1,0,0,0,0,0,0,0,2,0, + 0,0,11,0,0,0,67,0,0,0,115,52,0,0,0,121, + 14,116,0,124,0,131,1,106,1,125,1,87,0,110,24,4, + 0,116,2,107,10,114,38,1,0,1,0,1,0,100,1,125, + 1,89,0,110,2,88,0,124,1,100,2,79,0,125,1,124, + 1,83,0,41,3,122,51,67,97,108,99,117,108,97,116,101, + 32,116,104,101,32,109,111,100,101,32,112,101,114,109,105,115, + 115,105,111,110,115,32,102,111,114,32,97,32,98,121,116,101, + 99,111,100,101,32,102,105,108,101,46,105,182,1,0,0,233, + 128,0,0,0,41,3,114,41,0,0,0,114,43,0,0,0, + 114,42,0,0,0,41,2,114,37,0,0,0,114,44,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,5,95,119,114,97,112,147,1,0,0,115,8,0,0,0, - 0,1,10,1,10,1,22,1,122,26,95,99,104,101,99,107, - 95,110,97,109,101,46,60,108,111,99,97,108,115,62,46,95, - 119,114,97,112,41,1,78,41,3,218,10,95,98,111,111,116, - 115,116,114,97,112,114,117,0,0,0,218,9,78,97,109,101, - 69,114,114,111,114,41,3,114,106,0,0,0,114,107,0,0, - 0,114,117,0,0,0,114,4,0,0,0,41,1,114,106,0, - 0,0,114,6,0,0,0,218,11,95,99,104,101,99,107,95, - 110,97,109,101,128,1,0,0,115,14,0,0,0,0,8,14, - 7,2,1,10,1,14,2,14,5,10,1,114,120,0,0,0, - 99,2,0,0,0,0,0,0,0,5,0,0,0,4,0,0, - 0,67,0,0,0,115,60,0,0,0,124,0,106,0,124,1, - 131,1,92,2,125,2,125,3,124,2,100,1,107,8,114,56, - 116,1,124,3,131,1,114,56,100,2,125,4,116,2,106,3, - 124,4,106,4,124,3,100,3,25,0,131,1,116,5,131,2, - 1,0,124,2,83,0,41,4,122,155,84,114,121,32,116,111, - 32,102,105,110,100,32,97,32,108,111,97,100,101,114,32,102, - 111,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100, - 32,109,111,100,117,108,101,32,98,121,32,100,101,108,101,103, - 97,116,105,110,103,32,116,111,10,32,32,32,32,115,101,108, - 102,46,102,105,110,100,95,108,111,97,100,101,114,40,41,46, - 10,10,32,32,32,32,84,104,105,115,32,109,101,116,104,111, - 100,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32, - 105,110,32,102,97,118,111,114,32,111,102,32,102,105,110,100, - 101,114,46,102,105,110,100,95,115,112,101,99,40,41,46,10, - 10,32,32,32,32,78,122,44,78,111,116,32,105,109,112,111, - 114,116,105,110,103,32,100,105,114,101,99,116,111,114,121,32, - 123,125,58,32,109,105,115,115,105,110,103,32,95,95,105,110, - 105,116,95,95,114,62,0,0,0,41,6,218,11,102,105,110, - 100,95,108,111,97,100,101,114,114,33,0,0,0,114,63,0, - 0,0,114,64,0,0,0,114,50,0,0,0,218,13,73,109, - 112,111,114,116,87,97,114,110,105,110,103,41,5,114,104,0, - 0,0,218,8,102,117,108,108,110,97,109,101,218,6,108,111, - 97,100,101,114,218,8,112,111,114,116,105,111,110,115,218,3, - 109,115,103,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,17,95,102,105,110,100,95,109,111,100,117,108,101, - 95,115,104,105,109,156,1,0,0,115,10,0,0,0,0,10, - 14,1,16,1,4,1,22,1,114,127,0,0,0,99,4,0, - 0,0,0,0,0,0,11,0,0,0,22,0,0,0,67,0, - 0,0,115,136,1,0,0,105,0,125,4,124,2,100,1,107, - 9,114,22,124,2,124,4,100,2,60,0,110,4,100,3,125, - 2,124,3,100,1,107,9,114,42,124,3,124,4,100,4,60, - 0,124,0,100,1,100,5,133,2,25,0,125,5,124,0,100, - 5,100,6,133,2,25,0,125,6,124,0,100,6,100,7,133, - 2,25,0,125,7,124,5,116,0,107,3,114,124,100,8,106, - 1,124,2,124,5,131,2,125,8,116,2,106,3,100,9,124, - 8,131,2,1,0,116,4,124,8,102,1,124,4,142,1,130, - 1,110,86,116,5,124,6,131,1,100,5,107,3,114,168,100, - 10,106,1,124,2,131,1,125,8,116,2,106,3,100,9,124, - 8,131,2,1,0,116,6,124,8,131,1,130,1,110,42,116, - 5,124,7,131,1,100,5,107,3,114,210,100,11,106,1,124, - 2,131,1,125,8,116,2,106,3,100,9,124,8,131,2,1, - 0,116,6,124,8,131,1,130,1,124,1,100,1,107,9,144, - 1,114,124,121,16,116,7,124,1,100,12,25,0,131,1,125, - 9,87,0,110,22,4,0,116,8,107,10,144,1,114,2,1, - 0,1,0,1,0,89,0,110,50,88,0,116,9,124,6,131, - 1,124,9,107,3,144,1,114,52,100,13,106,1,124,2,131, + 218,10,95,99,97,108,99,95,109,111,100,101,116,1,0,0, + 115,12,0,0,0,0,2,2,1,14,1,14,1,10,3,8, + 1,114,101,0,0,0,99,1,0,0,0,0,0,0,0,3, + 0,0,0,11,0,0,0,3,0,0,0,115,68,0,0,0, + 100,6,135,0,102,1,100,2,100,3,132,9,125,1,121,10, + 116,0,106,1,125,2,87,0,110,28,4,0,116,2,107,10, + 114,52,1,0,1,0,1,0,100,4,100,5,132,0,125,2, + 89,0,110,2,88,0,124,2,124,1,136,0,131,2,1,0, + 124,1,83,0,41,7,122,252,68,101,99,111,114,97,116,111, + 114,32,116,111,32,118,101,114,105,102,121,32,116,104,97,116, + 32,116,104,101,32,109,111,100,117,108,101,32,98,101,105,110, + 103,32,114,101,113,117,101,115,116,101,100,32,109,97,116,99, + 104,101,115,32,116,104,101,32,111,110,101,32,116,104,101,10, + 32,32,32,32,108,111,97,100,101,114,32,99,97,110,32,104, + 97,110,100,108,101,46,10,10,32,32,32,32,84,104,101,32, + 102,105,114,115,116,32,97,114,103,117,109,101,110,116,32,40, + 115,101,108,102,41,32,109,117,115,116,32,100,101,102,105,110, + 101,32,95,110,97,109,101,32,119,104,105,99,104,32,116,104, + 101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110, + 116,32,105,115,10,32,32,32,32,99,111,109,112,97,114,101, + 100,32,97,103,97,105,110,115,116,46,32,73,102,32,116,104, + 101,32,99,111,109,112,97,114,105,115,111,110,32,102,97,105, + 108,115,32,116,104,101,110,32,73,109,112,111,114,116,69,114, + 114,111,114,32,105,115,32,114,97,105,115,101,100,46,10,10, + 32,32,32,32,78,99,2,0,0,0,0,0,0,0,4,0, + 0,0,4,0,0,0,31,0,0,0,115,66,0,0,0,124, + 1,100,0,107,8,114,16,124,0,106,0,125,1,110,32,124, + 0,106,0,124,1,107,3,114,48,116,1,100,1,124,0,106, + 0,124,1,102,2,22,0,124,1,100,2,141,2,130,1,136, + 0,124,0,124,1,102,2,124,2,158,2,124,3,142,1,83, + 0,41,3,78,122,30,108,111,97,100,101,114,32,102,111,114, + 32,37,115,32,99,97,110,110,111,116,32,104,97,110,100,108, + 101,32,37,115,41,1,218,4,110,97,109,101,41,2,114,102, + 0,0,0,218,11,73,109,112,111,114,116,69,114,114,111,114, + 41,4,218,4,115,101,108,102,114,102,0,0,0,218,4,97, + 114,103,115,90,6,107,119,97,114,103,115,41,1,218,6,109, + 101,116,104,111,100,114,4,0,0,0,114,6,0,0,0,218, + 19,95,99,104,101,99,107,95,110,97,109,101,95,119,114,97, + 112,112,101,114,136,1,0,0,115,12,0,0,0,0,1,8, + 1,8,1,10,1,4,1,18,1,122,40,95,99,104,101,99, + 107,95,110,97,109,101,46,60,108,111,99,97,108,115,62,46, + 95,99,104,101,99,107,95,110,97,109,101,95,119,114,97,112, + 112,101,114,99,2,0,0,0,0,0,0,0,3,0,0,0, + 7,0,0,0,83,0,0,0,115,60,0,0,0,120,40,100, + 5,68,0,93,32,125,2,116,0,124,1,124,2,131,2,114, + 6,116,1,124,0,124,2,116,2,124,1,124,2,131,2,131, + 3,1,0,113,6,87,0,124,0,106,3,106,4,124,1,106, + 3,131,1,1,0,100,0,83,0,41,6,78,218,10,95,95, + 109,111,100,117,108,101,95,95,218,8,95,95,110,97,109,101, + 95,95,218,12,95,95,113,117,97,108,110,97,109,101,95,95, + 218,7,95,95,100,111,99,95,95,41,4,114,108,0,0,0, + 114,109,0,0,0,114,110,0,0,0,114,111,0,0,0,41, + 5,218,7,104,97,115,97,116,116,114,218,7,115,101,116,97, + 116,116,114,218,7,103,101,116,97,116,116,114,218,8,95,95, + 100,105,99,116,95,95,218,6,117,112,100,97,116,101,41,3, + 90,3,110,101,119,90,3,111,108,100,114,55,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,5, + 95,119,114,97,112,147,1,0,0,115,8,0,0,0,0,1, + 10,1,10,1,22,1,122,26,95,99,104,101,99,107,95,110, + 97,109,101,46,60,108,111,99,97,108,115,62,46,95,119,114, + 97,112,41,1,78,41,3,218,10,95,98,111,111,116,115,116, + 114,97,112,114,117,0,0,0,218,9,78,97,109,101,69,114, + 114,111,114,41,3,114,106,0,0,0,114,107,0,0,0,114, + 117,0,0,0,114,4,0,0,0,41,1,114,106,0,0,0, + 114,6,0,0,0,218,11,95,99,104,101,99,107,95,110,97, + 109,101,128,1,0,0,115,14,0,0,0,0,8,14,7,2, + 1,10,1,14,2,14,5,10,1,114,120,0,0,0,99,2, + 0,0,0,0,0,0,0,5,0,0,0,4,0,0,0,67, + 0,0,0,115,60,0,0,0,124,0,106,0,124,1,131,1, + 92,2,125,2,125,3,124,2,100,1,107,8,114,56,116,1, + 124,3,131,1,114,56,100,2,125,4,116,2,106,3,124,4, + 106,4,124,3,100,3,25,0,131,1,116,5,131,2,1,0, + 124,2,83,0,41,4,122,155,84,114,121,32,116,111,32,102, + 105,110,100,32,97,32,108,111,97,100,101,114,32,102,111,114, + 32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,109, + 111,100,117,108,101,32,98,121,32,100,101,108,101,103,97,116, + 105,110,103,32,116,111,10,32,32,32,32,115,101,108,102,46, + 102,105,110,100,95,108,111,97,100,101,114,40,41,46,10,10, + 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32, + 105,115,32,100,101,112,114,101,99,97,116,101,100,32,105,110, + 32,102,97,118,111,114,32,111,102,32,102,105,110,100,101,114, + 46,102,105,110,100,95,115,112,101,99,40,41,46,10,10,32, + 32,32,32,78,122,44,78,111,116,32,105,109,112,111,114,116, + 105,110,103,32,100,105,114,101,99,116,111,114,121,32,123,125, + 58,32,109,105,115,115,105,110,103,32,95,95,105,110,105,116, + 95,95,114,62,0,0,0,41,6,218,11,102,105,110,100,95, + 108,111,97,100,101,114,114,33,0,0,0,114,63,0,0,0, + 114,64,0,0,0,114,50,0,0,0,218,13,73,109,112,111, + 114,116,87,97,114,110,105,110,103,41,5,114,104,0,0,0, + 218,8,102,117,108,108,110,97,109,101,218,6,108,111,97,100, + 101,114,218,8,112,111,114,116,105,111,110,115,218,3,109,115, + 103,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,17,95,102,105,110,100,95,109,111,100,117,108,101,95,115, + 104,105,109,156,1,0,0,115,10,0,0,0,0,10,14,1, + 16,1,4,1,22,1,114,127,0,0,0,99,4,0,0,0, + 0,0,0,0,11,0,0,0,22,0,0,0,67,0,0,0, + 115,136,1,0,0,105,0,125,4,124,2,100,1,107,9,114, + 22,124,2,124,4,100,2,60,0,110,4,100,3,125,2,124, + 3,100,1,107,9,114,42,124,3,124,4,100,4,60,0,124, + 0,100,1,100,5,133,2,25,0,125,5,124,0,100,5,100, + 6,133,2,25,0,125,6,124,0,100,6,100,7,133,2,25, + 0,125,7,124,5,116,0,107,3,114,124,100,8,106,1,124, + 2,124,5,131,2,125,8,116,2,106,3,100,9,124,8,131, + 2,1,0,116,4,124,8,102,1,124,4,142,1,130,1,110, + 86,116,5,124,6,131,1,100,5,107,3,114,168,100,10,106, + 1,124,2,131,1,125,8,116,2,106,3,100,9,124,8,131, + 2,1,0,116,6,124,8,131,1,130,1,110,42,116,5,124, + 7,131,1,100,5,107,3,114,210,100,11,106,1,124,2,131, 1,125,8,116,2,106,3,100,9,124,8,131,2,1,0,116, - 4,124,8,102,1,124,4,142,1,130,1,121,16,124,1,100, - 14,25,0,100,15,64,0,125,10,87,0,110,22,4,0,116, - 8,107,10,144,1,114,90,1,0,1,0,1,0,89,0,110, - 34,88,0,116,9,124,7,131,1,124,10,107,3,144,1,114, - 124,116,4,100,13,106,1,124,2,131,1,102,1,124,4,142, - 1,130,1,124,0,100,7,100,1,133,2,25,0,83,0,41, - 16,97,122,1,0,0,86,97,108,105,100,97,116,101,32,116, - 104,101,32,104,101,97,100,101,114,32,111,102,32,116,104,101, - 32,112,97,115,115,101,100,45,105,110,32,98,121,116,101,99, - 111,100,101,32,97,103,97,105,110,115,116,32,115,111,117,114, - 99,101,95,115,116,97,116,115,32,40,105,102,10,32,32,32, - 32,103,105,118,101,110,41,32,97,110,100,32,114,101,116,117, - 114,110,105,110,103,32,116,104,101,32,98,121,116,101,99,111, - 100,101,32,116,104,97,116,32,99,97,110,32,98,101,32,99, - 111,109,112,105,108,101,100,32,98,121,32,99,111,109,112,105, - 108,101,40,41,46,10,10,32,32,32,32,65,108,108,32,111, - 116,104,101,114,32,97,114,103,117,109,101,110,116,115,32,97, - 114,101,32,117,115,101,100,32,116,111,32,101,110,104,97,110, - 99,101,32,101,114,114,111,114,32,114,101,112,111,114,116,105, - 110,103,46,10,10,32,32,32,32,73,109,112,111,114,116,69, - 114,114,111,114,32,105,115,32,114,97,105,115,101,100,32,119, - 104,101,110,32,116,104,101,32,109,97,103,105,99,32,110,117, - 109,98,101,114,32,105,115,32,105,110,99,111,114,114,101,99, - 116,32,111,114,32,116,104,101,32,98,121,116,101,99,111,100, - 101,32,105,115,10,32,32,32,32,102,111,117,110,100,32,116, - 111,32,98,101,32,115,116,97,108,101,46,32,69,79,70,69, - 114,114,111,114,32,105,115,32,114,97,105,115,101,100,32,119, - 104,101,110,32,116,104,101,32,100,97,116,97,32,105,115,32, - 102,111,117,110,100,32,116,111,32,98,101,10,32,32,32,32, - 116,114,117,110,99,97,116,101,100,46,10,10,32,32,32,32, - 78,114,102,0,0,0,122,10,60,98,121,116,101,99,111,100, - 101,62,114,37,0,0,0,114,14,0,0,0,233,8,0,0, - 0,233,12,0,0,0,122,30,98,97,100,32,109,97,103,105, - 99,32,110,117,109,98,101,114,32,105,110,32,123,33,114,125, - 58,32,123,33,114,125,122,2,123,125,122,43,114,101,97,99, - 104,101,100,32,69,79,70,32,119,104,105,108,101,32,114,101, - 97,100,105,110,103,32,116,105,109,101,115,116,97,109,112,32, - 105,110,32,123,33,114,125,122,48,114,101,97,99,104,101,100, - 32,69,79,70,32,119,104,105,108,101,32,114,101,97,100,105, - 110,103,32,115,105,122,101,32,111,102,32,115,111,117,114,99, - 101,32,105,110,32,123,33,114,125,218,5,109,116,105,109,101, - 122,26,98,121,116,101,99,111,100,101,32,105,115,32,115,116, - 97,108,101,32,102,111,114,32,123,33,114,125,218,4,115,105, - 122,101,108,3,0,0,0,255,127,255,127,3,0,41,10,218, - 12,77,65,71,73,67,95,78,85,77,66,69,82,114,50,0, - 0,0,114,118,0,0,0,218,16,95,118,101,114,98,111,115, - 101,95,109,101,115,115,97,103,101,114,103,0,0,0,114,33, - 0,0,0,218,8,69,79,70,69,114,114,111,114,114,16,0, - 0,0,218,8,75,101,121,69,114,114,111,114,114,21,0,0, - 0,41,11,114,56,0,0,0,218,12,115,111,117,114,99,101, - 95,115,116,97,116,115,114,102,0,0,0,114,37,0,0,0, - 90,11,101,120,99,95,100,101,116,97,105,108,115,90,5,109, - 97,103,105,99,90,13,114,97,119,95,116,105,109,101,115,116, - 97,109,112,90,8,114,97,119,95,115,105,122,101,114,79,0, - 0,0,218,12,115,111,117,114,99,101,95,109,116,105,109,101, - 218,11,115,111,117,114,99,101,95,115,105,122,101,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,25,95,118, - 97,108,105,100,97,116,101,95,98,121,116,101,99,111,100,101, - 95,104,101,97,100,101,114,173,1,0,0,115,76,0,0,0, - 0,11,4,1,8,1,10,3,4,1,8,1,8,1,12,1, - 12,1,12,1,8,1,12,1,12,1,14,1,12,1,10,1, - 12,1,10,1,12,1,10,1,12,1,8,1,10,1,2,1, - 16,1,16,1,6,2,14,1,10,1,12,1,12,1,2,1, - 16,1,16,1,6,2,14,1,12,1,6,1,114,139,0,0, - 0,99,4,0,0,0,0,0,0,0,5,0,0,0,5,0, - 0,0,67,0,0,0,115,82,0,0,0,116,0,106,1,124, - 0,131,1,125,4,116,2,124,4,116,3,131,2,114,58,116, - 4,106,5,100,1,124,2,131,2,1,0,124,3,100,2,107, - 9,114,52,116,6,106,7,124,4,124,3,131,2,1,0,124, - 4,83,0,110,20,116,8,100,3,106,9,124,2,131,1,124, - 1,124,2,100,4,141,3,130,1,100,2,83,0,41,5,122, - 60,67,111,109,112,105,108,101,32,98,121,116,101,99,111,100, - 101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121, - 32,95,118,97,108,105,100,97,116,101,95,98,121,116,101,99, - 111,100,101,95,104,101,97,100,101,114,40,41,46,122,21,99, - 111,100,101,32,111,98,106,101,99,116,32,102,114,111,109,32, - 123,33,114,125,78,122,23,78,111,110,45,99,111,100,101,32, - 111,98,106,101,99,116,32,105,110,32,123,33,114,125,41,2, - 114,102,0,0,0,114,37,0,0,0,41,10,218,7,109,97, - 114,115,104,97,108,90,5,108,111,97,100,115,218,10,105,115, - 105,110,115,116,97,110,99,101,218,10,95,99,111,100,101,95, - 116,121,112,101,114,118,0,0,0,114,133,0,0,0,218,4, - 95,105,109,112,90,16,95,102,105,120,95,99,111,95,102,105, - 108,101,110,97,109,101,114,103,0,0,0,114,50,0,0,0, - 41,5,114,56,0,0,0,114,102,0,0,0,114,93,0,0, - 0,114,94,0,0,0,218,4,99,111,100,101,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,218,17,95,99,111, - 109,112,105,108,101,95,98,121,116,101,99,111,100,101,228,1, - 0,0,115,16,0,0,0,0,2,10,1,10,1,12,1,8, - 1,12,1,6,2,10,1,114,145,0,0,0,114,62,0,0, - 0,99,3,0,0,0,0,0,0,0,4,0,0,0,3,0, - 0,0,67,0,0,0,115,56,0,0,0,116,0,116,1,131, - 1,125,3,124,3,106,2,116,3,124,1,131,1,131,1,1, - 0,124,3,106,2,116,3,124,2,131,1,131,1,1,0,124, - 3,106,2,116,4,106,5,124,0,131,1,131,1,1,0,124, - 3,83,0,41,1,122,80,67,111,109,112,105,108,101,32,97, - 32,99,111,100,101,32,111,98,106,101,99,116,32,105,110,116, - 111,32,98,121,116,101,99,111,100,101,32,102,111,114,32,119, - 114,105,116,105,110,103,32,111,117,116,32,116,111,32,97,32, - 98,121,116,101,45,99,111,109,112,105,108,101,100,10,32,32, - 32,32,102,105,108,101,46,41,6,218,9,98,121,116,101,97, - 114,114,97,121,114,132,0,0,0,218,6,101,120,116,101,110, - 100,114,19,0,0,0,114,140,0,0,0,90,5,100,117,109, - 112,115,41,4,114,144,0,0,0,114,130,0,0,0,114,138, - 0,0,0,114,56,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,218,17,95,99,111,100,101,95,116, - 111,95,98,121,116,101,99,111,100,101,240,1,0,0,115,10, - 0,0,0,0,3,8,1,14,1,14,1,16,1,114,148,0, - 0,0,99,1,0,0,0,0,0,0,0,5,0,0,0,4, - 0,0,0,67,0,0,0,115,62,0,0,0,100,1,100,2, - 108,0,125,1,116,1,106,2,124,0,131,1,106,3,125,2, - 124,1,106,4,124,2,131,1,125,3,116,1,106,5,100,2, - 100,3,131,2,125,4,124,4,106,6,124,0,106,6,124,3, - 100,1,25,0,131,1,131,1,83,0,41,4,122,121,68,101, - 99,111,100,101,32,98,121,116,101,115,32,114,101,112,114,101, - 115,101,110,116,105,110,103,32,115,111,117,114,99,101,32,99, - 111,100,101,32,97,110,100,32,114,101,116,117,114,110,32,116, - 104,101,32,115,116,114,105,110,103,46,10,10,32,32,32,32, - 85,110,105,118,101,114,115,97,108,32,110,101,119,108,105,110, - 101,32,115,117,112,112,111,114,116,32,105,115,32,117,115,101, - 100,32,105,110,32,116,104,101,32,100,101,99,111,100,105,110, - 103,46,10,32,32,32,32,114,62,0,0,0,78,84,41,7, - 218,8,116,111,107,101,110,105,122,101,114,52,0,0,0,90, - 7,66,121,116,101,115,73,79,90,8,114,101,97,100,108,105, - 110,101,90,15,100,101,116,101,99,116,95,101,110,99,111,100, - 105,110,103,90,25,73,110,99,114,101,109,101,110,116,97,108, - 78,101,119,108,105,110,101,68,101,99,111,100,101,114,218,6, - 100,101,99,111,100,101,41,5,218,12,115,111,117,114,99,101, - 95,98,121,116,101,115,114,149,0,0,0,90,21,115,111,117, - 114,99,101,95,98,121,116,101,115,95,114,101,97,100,108,105, - 110,101,218,8,101,110,99,111,100,105,110,103,90,15,110,101, - 119,108,105,110,101,95,100,101,99,111,100,101,114,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,13,100,101, - 99,111,100,101,95,115,111,117,114,99,101,250,1,0,0,115, - 10,0,0,0,0,5,8,1,12,1,10,1,12,1,114,153, - 0,0,0,41,2,114,124,0,0,0,218,26,115,117,98,109, - 111,100,117,108,101,95,115,101,97,114,99,104,95,108,111,99, - 97,116,105,111,110,115,99,2,0,0,0,2,0,0,0,9, - 0,0,0,19,0,0,0,67,0,0,0,115,18,1,0,0, - 124,1,100,1,107,8,114,60,100,2,125,1,116,0,124,2, - 100,3,131,2,114,70,121,14,124,2,106,1,124,0,131,1, - 125,1,87,0,113,70,4,0,116,2,107,10,114,56,1,0, - 1,0,1,0,89,0,113,70,88,0,110,10,116,3,106,4, - 124,1,131,1,125,1,116,5,106,6,124,0,124,2,124,1, - 100,4,141,3,125,4,100,5,124,4,95,7,124,2,100,1, - 107,8,114,156,120,54,116,8,131,0,68,0,93,40,92,2, - 125,5,125,6,124,1,106,9,116,10,124,6,131,1,131,1, - 114,108,124,5,124,0,124,1,131,2,125,2,124,2,124,4, - 95,11,80,0,113,108,87,0,100,1,83,0,124,3,116,12, - 107,8,114,222,116,0,124,2,100,6,131,2,114,228,121,14, - 124,2,106,13,124,0,131,1,125,7,87,0,110,20,4,0, - 116,2,107,10,114,208,1,0,1,0,1,0,89,0,113,228, - 88,0,124,7,114,228,103,0,124,4,95,14,110,6,124,3, - 124,4,95,14,124,4,106,14,103,0,107,2,144,1,114,14, - 124,1,144,1,114,14,116,15,124,1,131,1,100,7,25,0, - 125,8,124,4,106,14,106,16,124,8,131,1,1,0,124,4, - 83,0,41,8,97,61,1,0,0,82,101,116,117,114,110,32, - 97,32,109,111,100,117,108,101,32,115,112,101,99,32,98,97, - 115,101,100,32,111,110,32,97,32,102,105,108,101,32,108,111, - 99,97,116,105,111,110,46,10,10,32,32,32,32,84,111,32, - 105,110,100,105,99,97,116,101,32,116,104,97,116,32,116,104, - 101,32,109,111,100,117,108,101,32,105,115,32,97,32,112,97, - 99,107,97,103,101,44,32,115,101,116,10,32,32,32,32,115, - 117,98,109,111,100,117,108,101,95,115,101,97,114,99,104,95, - 108,111,99,97,116,105,111,110,115,32,116,111,32,97,32,108, - 105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121, - 32,112,97,116,104,115,46,32,32,65,110,10,32,32,32,32, - 101,109,112,116,121,32,108,105,115,116,32,105,115,32,115,117, - 102,102,105,99,105,101,110,116,44,32,116,104,111,117,103,104, - 32,105,116,115,32,110,111,116,32,111,116,104,101,114,119,105, - 115,101,32,117,115,101,102,117,108,32,116,111,32,116,104,101, - 10,32,32,32,32,105,109,112,111,114,116,32,115,121,115,116, - 101,109,46,10,10,32,32,32,32,84,104,101,32,108,111,97, - 100,101,114,32,109,117,115,116,32,116,97,107,101,32,97,32, - 115,112,101,99,32,97,115,32,105,116,115,32,111,110,108,121, - 32,95,95,105,110,105,116,95,95,40,41,32,97,114,103,46, - 10,10,32,32,32,32,78,122,9,60,117,110,107,110,111,119, - 110,62,218,12,103,101,116,95,102,105,108,101,110,97,109,101, - 41,1,218,6,111,114,105,103,105,110,84,218,10,105,115,95, - 112,97,99,107,97,103,101,114,62,0,0,0,41,17,114,112, - 0,0,0,114,155,0,0,0,114,103,0,0,0,114,3,0, - 0,0,114,67,0,0,0,114,118,0,0,0,218,10,77,111, - 100,117,108,101,83,112,101,99,90,13,95,115,101,116,95,102, - 105,108,101,97,116,116,114,218,27,95,103,101,116,95,115,117, - 112,112,111,114,116,101,100,95,102,105,108,101,95,108,111,97, - 100,101,114,115,114,96,0,0,0,114,97,0,0,0,114,124, - 0,0,0,218,9,95,80,79,80,85,76,65,84,69,114,157, - 0,0,0,114,154,0,0,0,114,40,0,0,0,218,6,97, - 112,112,101,110,100,41,9,114,102,0,0,0,90,8,108,111, - 99,97,116,105,111,110,114,124,0,0,0,114,154,0,0,0, - 218,4,115,112,101,99,218,12,108,111,97,100,101,114,95,99, - 108,97,115,115,218,8,115,117,102,102,105,120,101,115,114,157, - 0,0,0,90,7,100,105,114,110,97,109,101,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,218,23,115,112,101, - 99,95,102,114,111,109,95,102,105,108,101,95,108,111,99,97, - 116,105,111,110,11,2,0,0,115,62,0,0,0,0,12,8, - 4,4,1,10,2,2,1,14,1,14,1,8,2,10,8,16, - 1,6,3,8,1,16,1,14,1,10,1,6,1,6,2,4, - 3,8,2,10,1,2,1,14,1,14,1,6,2,4,1,8, - 2,6,1,12,1,6,1,12,1,12,2,114,165,0,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, - 0,64,0,0,0,115,80,0,0,0,101,0,90,1,100,0, - 90,2,100,1,90,3,100,2,90,4,100,3,90,5,100,4, - 90,6,101,7,100,5,100,6,132,0,131,1,90,8,101,7, - 100,7,100,8,132,0,131,1,90,9,101,7,100,14,100,10, - 100,11,132,1,131,1,90,10,101,7,100,15,100,12,100,13, - 132,1,131,1,90,11,100,9,83,0,41,16,218,21,87,105, + 6,124,8,131,1,130,1,124,1,100,1,107,9,144,1,114, + 124,121,16,116,7,124,1,100,12,25,0,131,1,125,9,87, + 0,110,22,4,0,116,8,107,10,144,1,114,2,1,0,1, + 0,1,0,89,0,110,50,88,0,116,9,124,6,131,1,124, + 9,107,3,144,1,114,52,100,13,106,1,124,2,131,1,125, + 8,116,2,106,3,100,9,124,8,131,2,1,0,116,4,124, + 8,102,1,124,4,142,1,130,1,121,16,124,1,100,14,25, + 0,100,15,64,0,125,10,87,0,110,22,4,0,116,8,107, + 10,144,1,114,90,1,0,1,0,1,0,89,0,110,34,88, + 0,116,9,124,7,131,1,124,10,107,3,144,1,114,124,116, + 4,100,13,106,1,124,2,131,1,102,1,124,4,142,1,130, + 1,124,0,100,7,100,1,133,2,25,0,83,0,41,16,97, + 122,1,0,0,86,97,108,105,100,97,116,101,32,116,104,101, + 32,104,101,97,100,101,114,32,111,102,32,116,104,101,32,112, + 97,115,115,101,100,45,105,110,32,98,121,116,101,99,111,100, + 101,32,97,103,97,105,110,115,116,32,115,111,117,114,99,101, + 95,115,116,97,116,115,32,40,105,102,10,32,32,32,32,103, + 105,118,101,110,41,32,97,110,100,32,114,101,116,117,114,110, + 105,110,103,32,116,104,101,32,98,121,116,101,99,111,100,101, + 32,116,104,97,116,32,99,97,110,32,98,101,32,99,111,109, + 112,105,108,101,100,32,98,121,32,99,111,109,112,105,108,101, + 40,41,46,10,10,32,32,32,32,65,108,108,32,111,116,104, + 101,114,32,97,114,103,117,109,101,110,116,115,32,97,114,101, + 32,117,115,101,100,32,116,111,32,101,110,104,97,110,99,101, + 32,101,114,114,111,114,32,114,101,112,111,114,116,105,110,103, + 46,10,10,32,32,32,32,73,109,112,111,114,116,69,114,114, + 111,114,32,105,115,32,114,97,105,115,101,100,32,119,104,101, + 110,32,116,104,101,32,109,97,103,105,99,32,110,117,109,98, + 101,114,32,105,115,32,105,110,99,111,114,114,101,99,116,32, + 111,114,32,116,104,101,32,98,121,116,101,99,111,100,101,32, + 105,115,10,32,32,32,32,102,111,117,110,100,32,116,111,32, + 98,101,32,115,116,97,108,101,46,32,69,79,70,69,114,114, + 111,114,32,105,115,32,114,97,105,115,101,100,32,119,104,101, + 110,32,116,104,101,32,100,97,116,97,32,105,115,32,102,111, + 117,110,100,32,116,111,32,98,101,10,32,32,32,32,116,114, + 117,110,99,97,116,101,100,46,10,10,32,32,32,32,78,114, + 102,0,0,0,122,10,60,98,121,116,101,99,111,100,101,62, + 114,37,0,0,0,114,14,0,0,0,233,8,0,0,0,233, + 12,0,0,0,122,30,98,97,100,32,109,97,103,105,99,32, + 110,117,109,98,101,114,32,105,110,32,123,33,114,125,58,32, + 123,33,114,125,122,2,123,125,122,43,114,101,97,99,104,101, + 100,32,69,79,70,32,119,104,105,108,101,32,114,101,97,100, + 105,110,103,32,116,105,109,101,115,116,97,109,112,32,105,110, + 32,123,33,114,125,122,48,114,101,97,99,104,101,100,32,69, + 79,70,32,119,104,105,108,101,32,114,101,97,100,105,110,103, + 32,115,105,122,101,32,111,102,32,115,111,117,114,99,101,32, + 105,110,32,123,33,114,125,218,5,109,116,105,109,101,122,26, + 98,121,116,101,99,111,100,101,32,105,115,32,115,116,97,108, + 101,32,102,111,114,32,123,33,114,125,218,4,115,105,122,101, + 108,3,0,0,0,255,127,255,127,3,0,41,10,218,12,77, + 65,71,73,67,95,78,85,77,66,69,82,114,50,0,0,0, + 114,118,0,0,0,218,16,95,118,101,114,98,111,115,101,95, + 109,101,115,115,97,103,101,114,103,0,0,0,114,33,0,0, + 0,218,8,69,79,70,69,114,114,111,114,114,16,0,0,0, + 218,8,75,101,121,69,114,114,111,114,114,21,0,0,0,41, + 11,114,56,0,0,0,218,12,115,111,117,114,99,101,95,115, + 116,97,116,115,114,102,0,0,0,114,37,0,0,0,90,11, + 101,120,99,95,100,101,116,97,105,108,115,90,5,109,97,103, + 105,99,90,13,114,97,119,95,116,105,109,101,115,116,97,109, + 112,90,8,114,97,119,95,115,105,122,101,114,79,0,0,0, + 218,12,115,111,117,114,99,101,95,109,116,105,109,101,218,11, + 115,111,117,114,99,101,95,115,105,122,101,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,25,95,118,97,108, + 105,100,97,116,101,95,98,121,116,101,99,111,100,101,95,104, + 101,97,100,101,114,173,1,0,0,115,76,0,0,0,0,11, + 4,1,8,1,10,3,4,1,8,1,8,1,12,1,12,1, + 12,1,8,1,12,1,12,1,14,1,12,1,10,1,12,1, + 10,1,12,1,10,1,12,1,8,1,10,1,2,1,16,1, + 16,1,6,2,14,1,10,1,12,1,12,1,2,1,16,1, + 16,1,6,2,14,1,12,1,6,1,114,139,0,0,0,99, + 4,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0, + 67,0,0,0,115,80,0,0,0,116,0,106,1,124,0,131, + 1,125,4,116,2,124,4,116,3,131,2,114,56,116,4,106, + 5,100,1,124,2,131,2,1,0,124,3,100,2,107,9,114, + 52,116,6,106,7,124,4,124,3,131,2,1,0,124,4,83, + 0,116,8,100,3,106,9,124,2,131,1,124,1,124,2,100, + 4,141,3,130,1,100,2,83,0,41,5,122,60,67,111,109, + 112,105,108,101,32,98,121,116,101,99,111,100,101,32,97,115, + 32,114,101,116,117,114,110,101,100,32,98,121,32,95,118,97, + 108,105,100,97,116,101,95,98,121,116,101,99,111,100,101,95, + 104,101,97,100,101,114,40,41,46,122,21,99,111,100,101,32, + 111,98,106,101,99,116,32,102,114,111,109,32,123,33,114,125, + 78,122,23,78,111,110,45,99,111,100,101,32,111,98,106,101, + 99,116,32,105,110,32,123,33,114,125,41,2,114,102,0,0, + 0,114,37,0,0,0,41,10,218,7,109,97,114,115,104,97, + 108,90,5,108,111,97,100,115,218,10,105,115,105,110,115,116, + 97,110,99,101,218,10,95,99,111,100,101,95,116,121,112,101, + 114,118,0,0,0,114,133,0,0,0,218,4,95,105,109,112, + 90,16,95,102,105,120,95,99,111,95,102,105,108,101,110,97, + 109,101,114,103,0,0,0,114,50,0,0,0,41,5,114,56, + 0,0,0,114,102,0,0,0,114,93,0,0,0,114,94,0, + 0,0,218,4,99,111,100,101,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,17,95,99,111,109,112,105,108, + 101,95,98,121,116,101,99,111,100,101,228,1,0,0,115,16, + 0,0,0,0,2,10,1,10,1,12,1,8,1,12,1,4, + 2,10,1,114,145,0,0,0,114,62,0,0,0,99,3,0, + 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0, + 0,0,115,56,0,0,0,116,0,116,1,131,1,125,3,124, + 3,106,2,116,3,124,1,131,1,131,1,1,0,124,3,106, + 2,116,3,124,2,131,1,131,1,1,0,124,3,106,2,116, + 4,106,5,124,0,131,1,131,1,1,0,124,3,83,0,41, + 1,122,80,67,111,109,112,105,108,101,32,97,32,99,111,100, + 101,32,111,98,106,101,99,116,32,105,110,116,111,32,98,121, + 116,101,99,111,100,101,32,102,111,114,32,119,114,105,116,105, + 110,103,32,111,117,116,32,116,111,32,97,32,98,121,116,101, + 45,99,111,109,112,105,108,101,100,10,32,32,32,32,102,105, + 108,101,46,41,6,218,9,98,121,116,101,97,114,114,97,121, + 114,132,0,0,0,218,6,101,120,116,101,110,100,114,19,0, + 0,0,114,140,0,0,0,90,5,100,117,109,112,115,41,4, + 114,144,0,0,0,114,130,0,0,0,114,138,0,0,0,114, + 56,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,218,17,95,99,111,100,101,95,116,111,95,98,121, + 116,101,99,111,100,101,240,1,0,0,115,10,0,0,0,0, + 3,8,1,14,1,14,1,16,1,114,148,0,0,0,99,1, + 0,0,0,0,0,0,0,5,0,0,0,4,0,0,0,67, + 0,0,0,115,62,0,0,0,100,1,100,2,108,0,125,1, + 116,1,106,2,124,0,131,1,106,3,125,2,124,1,106,4, + 124,2,131,1,125,3,116,1,106,5,100,2,100,3,131,2, + 125,4,124,4,106,6,124,0,106,6,124,3,100,1,25,0, + 131,1,131,1,83,0,41,4,122,121,68,101,99,111,100,101, + 32,98,121,116,101,115,32,114,101,112,114,101,115,101,110,116, + 105,110,103,32,115,111,117,114,99,101,32,99,111,100,101,32, + 97,110,100,32,114,101,116,117,114,110,32,116,104,101,32,115, + 116,114,105,110,103,46,10,10,32,32,32,32,85,110,105,118, + 101,114,115,97,108,32,110,101,119,108,105,110,101,32,115,117, + 112,112,111,114,116,32,105,115,32,117,115,101,100,32,105,110, + 32,116,104,101,32,100,101,99,111,100,105,110,103,46,10,32, + 32,32,32,114,62,0,0,0,78,84,41,7,218,8,116,111, + 107,101,110,105,122,101,114,52,0,0,0,90,7,66,121,116, + 101,115,73,79,90,8,114,101,97,100,108,105,110,101,90,15, + 100,101,116,101,99,116,95,101,110,99,111,100,105,110,103,90, + 25,73,110,99,114,101,109,101,110,116,97,108,78,101,119,108, + 105,110,101,68,101,99,111,100,101,114,218,6,100,101,99,111, + 100,101,41,5,218,12,115,111,117,114,99,101,95,98,121,116, + 101,115,114,149,0,0,0,90,21,115,111,117,114,99,101,95, + 98,121,116,101,115,95,114,101,97,100,108,105,110,101,218,8, + 101,110,99,111,100,105,110,103,90,15,110,101,119,108,105,110, + 101,95,100,101,99,111,100,101,114,114,4,0,0,0,114,4, + 0,0,0,114,6,0,0,0,218,13,100,101,99,111,100,101, + 95,115,111,117,114,99,101,250,1,0,0,115,10,0,0,0, + 0,5,8,1,12,1,10,1,12,1,114,153,0,0,0,41, + 2,114,124,0,0,0,218,26,115,117,98,109,111,100,117,108, + 101,95,115,101,97,114,99,104,95,108,111,99,97,116,105,111, + 110,115,99,2,0,0,0,2,0,0,0,9,0,0,0,19, + 0,0,0,67,0,0,0,115,18,1,0,0,124,1,100,1, + 107,8,114,60,100,2,125,1,116,0,124,2,100,3,131,2, + 114,70,121,14,124,2,106,1,124,0,131,1,125,1,87,0, + 113,70,4,0,116,2,107,10,114,56,1,0,1,0,1,0, + 89,0,113,70,88,0,110,10,116,3,106,4,124,1,131,1, + 125,1,116,5,106,6,124,0,124,2,124,1,100,4,141,3, + 125,4,100,5,124,4,95,7,124,2,100,1,107,8,114,156, + 120,54,116,8,131,0,68,0,93,40,92,2,125,5,125,6, + 124,1,106,9,116,10,124,6,131,1,131,1,114,108,124,5, + 124,0,124,1,131,2,125,2,124,2,124,4,95,11,80,0, + 113,108,87,0,100,1,83,0,124,3,116,12,107,8,114,222, + 116,0,124,2,100,6,131,2,114,228,121,14,124,2,106,13, + 124,0,131,1,125,7,87,0,110,20,4,0,116,2,107,10, + 114,208,1,0,1,0,1,0,89,0,113,228,88,0,124,7, + 114,228,103,0,124,4,95,14,110,6,124,3,124,4,95,14, + 124,4,106,14,103,0,107,2,144,1,114,14,124,1,144,1, + 114,14,116,15,124,1,131,1,100,7,25,0,125,8,124,4, + 106,14,106,16,124,8,131,1,1,0,124,4,83,0,41,8, + 97,61,1,0,0,82,101,116,117,114,110,32,97,32,109,111, + 100,117,108,101,32,115,112,101,99,32,98,97,115,101,100,32, + 111,110,32,97,32,102,105,108,101,32,108,111,99,97,116,105, + 111,110,46,10,10,32,32,32,32,84,111,32,105,110,100,105, + 99,97,116,101,32,116,104,97,116,32,116,104,101,32,109,111, + 100,117,108,101,32,105,115,32,97,32,112,97,99,107,97,103, + 101,44,32,115,101,116,10,32,32,32,32,115,117,98,109,111, + 100,117,108,101,95,115,101,97,114,99,104,95,108,111,99,97, + 116,105,111,110,115,32,116,111,32,97,32,108,105,115,116,32, + 111,102,32,100,105,114,101,99,116,111,114,121,32,112,97,116, + 104,115,46,32,32,65,110,10,32,32,32,32,101,109,112,116, + 121,32,108,105,115,116,32,105,115,32,115,117,102,102,105,99, + 105,101,110,116,44,32,116,104,111,117,103,104,32,105,116,115, + 32,110,111,116,32,111,116,104,101,114,119,105,115,101,32,117, + 115,101,102,117,108,32,116,111,32,116,104,101,10,32,32,32, + 32,105,109,112,111,114,116,32,115,121,115,116,101,109,46,10, + 10,32,32,32,32,84,104,101,32,108,111,97,100,101,114,32, + 109,117,115,116,32,116,97,107,101,32,97,32,115,112,101,99, + 32,97,115,32,105,116,115,32,111,110,108,121,32,95,95,105, + 110,105,116,95,95,40,41,32,97,114,103,46,10,10,32,32, + 32,32,78,122,9,60,117,110,107,110,111,119,110,62,218,12, + 103,101,116,95,102,105,108,101,110,97,109,101,41,1,218,6, + 111,114,105,103,105,110,84,218,10,105,115,95,112,97,99,107, + 97,103,101,114,62,0,0,0,41,17,114,112,0,0,0,114, + 155,0,0,0,114,103,0,0,0,114,3,0,0,0,114,67, + 0,0,0,114,118,0,0,0,218,10,77,111,100,117,108,101, + 83,112,101,99,90,13,95,115,101,116,95,102,105,108,101,97, + 116,116,114,218,27,95,103,101,116,95,115,117,112,112,111,114, + 116,101,100,95,102,105,108,101,95,108,111,97,100,101,114,115, + 114,96,0,0,0,114,97,0,0,0,114,124,0,0,0,218, + 9,95,80,79,80,85,76,65,84,69,114,157,0,0,0,114, + 154,0,0,0,114,40,0,0,0,218,6,97,112,112,101,110, + 100,41,9,114,102,0,0,0,90,8,108,111,99,97,116,105, + 111,110,114,124,0,0,0,114,154,0,0,0,218,4,115,112, + 101,99,218,12,108,111,97,100,101,114,95,99,108,97,115,115, + 218,8,115,117,102,102,105,120,101,115,114,157,0,0,0,90, + 7,100,105,114,110,97,109,101,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,23,115,112,101,99,95,102,114, + 111,109,95,102,105,108,101,95,108,111,99,97,116,105,111,110, + 11,2,0,0,115,62,0,0,0,0,12,8,4,4,1,10, + 2,2,1,14,1,14,1,8,2,10,8,16,1,6,3,8, + 1,16,1,14,1,10,1,6,1,6,2,4,3,8,2,10, + 1,2,1,14,1,14,1,6,2,4,1,8,2,6,1,12, + 1,6,1,12,1,12,2,114,165,0,0,0,99,0,0,0, + 0,0,0,0,0,0,0,0,0,4,0,0,0,64,0,0, + 0,115,80,0,0,0,101,0,90,1,100,0,90,2,100,1, + 90,3,100,2,90,4,100,3,90,5,100,4,90,6,101,7, + 100,5,100,6,132,0,131,1,90,8,101,7,100,7,100,8, + 132,0,131,1,90,9,101,7,100,14,100,10,100,11,132,1, + 131,1,90,10,101,7,100,15,100,12,100,13,132,1,131,1, + 90,11,100,9,83,0,41,16,218,21,87,105,110,100,111,119, + 115,82,101,103,105,115,116,114,121,70,105,110,100,101,114,122, + 62,77,101,116,97,32,112,97,116,104,32,102,105,110,100,101, + 114,32,102,111,114,32,109,111,100,117,108,101,115,32,100,101, + 99,108,97,114,101,100,32,105,110,32,116,104,101,32,87,105, + 110,100,111,119,115,32,114,101,103,105,115,116,114,121,46,122, + 59,83,111,102,116,119,97,114,101,92,80,121,116,104,111,110, + 92,80,121,116,104,111,110,67,111,114,101,92,123,115,121,115, + 95,118,101,114,115,105,111,110,125,92,77,111,100,117,108,101, + 115,92,123,102,117,108,108,110,97,109,101,125,122,65,83,111, + 102,116,119,97,114,101,92,80,121,116,104,111,110,92,80,121, + 116,104,111,110,67,111,114,101,92,123,115,121,115,95,118,101, + 114,115,105,111,110,125,92,77,111,100,117,108,101,115,92,123, + 102,117,108,108,110,97,109,101,125,92,68,101,98,117,103,70, + 99,2,0,0,0,0,0,0,0,2,0,0,0,11,0,0, + 0,67,0,0,0,115,50,0,0,0,121,14,116,0,106,1, + 116,0,106,2,124,1,131,2,83,0,4,0,116,3,107,10, + 114,44,1,0,1,0,1,0,116,0,106,1,116,0,106,4, + 124,1,131,2,83,0,88,0,100,0,83,0,41,1,78,41, + 5,218,7,95,119,105,110,114,101,103,90,7,79,112,101,110, + 75,101,121,90,17,72,75,69,89,95,67,85,82,82,69,78, + 84,95,85,83,69,82,114,42,0,0,0,90,18,72,75,69, + 89,95,76,79,67,65,76,95,77,65,67,72,73,78,69,41, + 2,218,3,99,108,115,114,5,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,14,95,111,112,101, + 110,95,114,101,103,105,115,116,114,121,91,2,0,0,115,8, + 0,0,0,0,2,2,1,14,1,14,1,122,36,87,105,110, + 100,111,119,115,82,101,103,105,115,116,114,121,70,105,110,100, + 101,114,46,95,111,112,101,110,95,114,101,103,105,115,116,114, + 121,99,2,0,0,0,0,0,0,0,6,0,0,0,16,0, + 0,0,67,0,0,0,115,112,0,0,0,124,0,106,0,114, + 14,124,0,106,1,125,2,110,6,124,0,106,2,125,2,124, + 2,106,3,124,1,100,1,116,4,106,5,100,0,100,2,133, + 2,25,0,22,0,100,3,141,2,125,3,121,38,124,0,106, + 6,124,3,131,1,143,18,125,4,116,7,106,8,124,4,100, + 4,131,2,125,5,87,0,100,0,81,0,82,0,88,0,87, + 0,110,20,4,0,116,9,107,10,114,106,1,0,1,0,1, + 0,100,0,83,0,88,0,124,5,83,0,41,5,78,122,5, + 37,100,46,37,100,114,59,0,0,0,41,2,114,123,0,0, + 0,90,11,115,121,115,95,118,101,114,115,105,111,110,114,32, + 0,0,0,41,10,218,11,68,69,66,85,71,95,66,85,73, + 76,68,218,18,82,69,71,73,83,84,82,89,95,75,69,89, + 95,68,69,66,85,71,218,12,82,69,71,73,83,84,82,89, + 95,75,69,89,114,50,0,0,0,114,8,0,0,0,218,12, + 118,101,114,115,105,111,110,95,105,110,102,111,114,169,0,0, + 0,114,167,0,0,0,90,10,81,117,101,114,121,86,97,108, + 117,101,114,42,0,0,0,41,6,114,168,0,0,0,114,123, + 0,0,0,90,12,114,101,103,105,115,116,114,121,95,107,101, + 121,114,5,0,0,0,90,4,104,107,101,121,218,8,102,105, + 108,101,112,97,116,104,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,218,16,95,115,101,97,114,99,104,95,114, + 101,103,105,115,116,114,121,98,2,0,0,115,22,0,0,0, + 0,2,6,1,8,2,6,1,6,1,22,1,2,1,12,1, + 26,1,14,1,6,1,122,38,87,105,110,100,111,119,115,82, + 101,103,105,115,116,114,121,70,105,110,100,101,114,46,95,115, + 101,97,114,99,104,95,114,101,103,105,115,116,114,121,78,99, + 4,0,0,0,0,0,0,0,8,0,0,0,14,0,0,0, + 67,0,0,0,115,120,0,0,0,124,0,106,0,124,1,131, + 1,125,4,124,4,100,0,107,8,114,22,100,0,83,0,121, + 12,116,1,124,4,131,1,1,0,87,0,110,20,4,0,116, + 2,107,10,114,54,1,0,1,0,1,0,100,0,83,0,88, + 0,120,58,116,3,131,0,68,0,93,48,92,2,125,5,125, + 6,124,4,106,4,116,5,124,6,131,1,131,1,114,64,116, + 6,106,7,124,1,124,5,124,1,124,4,131,2,124,4,100, + 1,141,3,125,7,124,7,83,0,113,64,87,0,100,0,83, + 0,41,2,78,41,1,114,156,0,0,0,41,8,114,175,0, + 0,0,114,41,0,0,0,114,42,0,0,0,114,159,0,0, + 0,114,96,0,0,0,114,97,0,0,0,114,118,0,0,0, + 218,16,115,112,101,99,95,102,114,111,109,95,108,111,97,100, + 101,114,41,8,114,168,0,0,0,114,123,0,0,0,114,37, + 0,0,0,218,6,116,97,114,103,101,116,114,174,0,0,0, + 114,124,0,0,0,114,164,0,0,0,114,162,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,9, + 102,105,110,100,95,115,112,101,99,113,2,0,0,115,26,0, + 0,0,0,2,10,1,8,1,4,1,2,1,12,1,14,1, + 6,1,16,1,14,1,6,1,8,1,8,1,122,31,87,105, 110,100,111,119,115,82,101,103,105,115,116,114,121,70,105,110, - 100,101,114,122,62,77,101,116,97,32,112,97,116,104,32,102, - 105,110,100,101,114,32,102,111,114,32,109,111,100,117,108,101, - 115,32,100,101,99,108,97,114,101,100,32,105,110,32,116,104, - 101,32,87,105,110,100,111,119,115,32,114,101,103,105,115,116, - 114,121,46,122,59,83,111,102,116,119,97,114,101,92,80,121, - 116,104,111,110,92,80,121,116,104,111,110,67,111,114,101,92, - 123,115,121,115,95,118,101,114,115,105,111,110,125,92,77,111, - 100,117,108,101,115,92,123,102,117,108,108,110,97,109,101,125, - 122,65,83,111,102,116,119,97,114,101,92,80,121,116,104,111, - 110,92,80,121,116,104,111,110,67,111,114,101,92,123,115,121, - 115,95,118,101,114,115,105,111,110,125,92,77,111,100,117,108, - 101,115,92,123,102,117,108,108,110,97,109,101,125,92,68,101, - 98,117,103,70,99,2,0,0,0,0,0,0,0,2,0,0, - 0,11,0,0,0,67,0,0,0,115,50,0,0,0,121,14, - 116,0,106,1,116,0,106,2,124,1,131,2,83,0,4,0, - 116,3,107,10,114,44,1,0,1,0,1,0,116,0,106,1, - 116,0,106,4,124,1,131,2,83,0,88,0,100,0,83,0, - 41,1,78,41,5,218,7,95,119,105,110,114,101,103,90,7, - 79,112,101,110,75,101,121,90,17,72,75,69,89,95,67,85, - 82,82,69,78,84,95,85,83,69,82,114,42,0,0,0,90, - 18,72,75,69,89,95,76,79,67,65,76,95,77,65,67,72, - 73,78,69,41,2,218,3,99,108,115,114,5,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,14, - 95,111,112,101,110,95,114,101,103,105,115,116,114,121,91,2, - 0,0,115,8,0,0,0,0,2,2,1,14,1,14,1,122, - 36,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, - 70,105,110,100,101,114,46,95,111,112,101,110,95,114,101,103, - 105,115,116,114,121,99,2,0,0,0,0,0,0,0,6,0, - 0,0,16,0,0,0,67,0,0,0,115,112,0,0,0,124, - 0,106,0,114,14,124,0,106,1,125,2,110,6,124,0,106, - 2,125,2,124,2,106,3,124,1,100,1,116,4,106,5,100, - 0,100,2,133,2,25,0,22,0,100,3,141,2,125,3,121, - 38,124,0,106,6,124,3,131,1,143,18,125,4,116,7,106, - 8,124,4,100,4,131,2,125,5,87,0,100,0,81,0,82, - 0,88,0,87,0,110,20,4,0,116,9,107,10,114,106,1, - 0,1,0,1,0,100,0,83,0,88,0,124,5,83,0,41, - 5,78,122,5,37,100,46,37,100,114,59,0,0,0,41,2, - 114,123,0,0,0,90,11,115,121,115,95,118,101,114,115,105, - 111,110,114,32,0,0,0,41,10,218,11,68,69,66,85,71, - 95,66,85,73,76,68,218,18,82,69,71,73,83,84,82,89, - 95,75,69,89,95,68,69,66,85,71,218,12,82,69,71,73, - 83,84,82,89,95,75,69,89,114,50,0,0,0,114,8,0, - 0,0,218,12,118,101,114,115,105,111,110,95,105,110,102,111, - 114,169,0,0,0,114,167,0,0,0,90,10,81,117,101,114, - 121,86,97,108,117,101,114,42,0,0,0,41,6,114,168,0, - 0,0,114,123,0,0,0,90,12,114,101,103,105,115,116,114, - 121,95,107,101,121,114,5,0,0,0,90,4,104,107,101,121, - 218,8,102,105,108,101,112,97,116,104,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,218,16,95,115,101,97,114, - 99,104,95,114,101,103,105,115,116,114,121,98,2,0,0,115, - 22,0,0,0,0,2,6,1,8,2,6,1,6,1,22,1, - 2,1,12,1,26,1,14,1,6,1,122,38,87,105,110,100, - 111,119,115,82,101,103,105,115,116,114,121,70,105,110,100,101, - 114,46,95,115,101,97,114,99,104,95,114,101,103,105,115,116, - 114,121,78,99,4,0,0,0,0,0,0,0,8,0,0,0, - 14,0,0,0,67,0,0,0,115,120,0,0,0,124,0,106, - 0,124,1,131,1,125,4,124,4,100,0,107,8,114,22,100, - 0,83,0,121,12,116,1,124,4,131,1,1,0,87,0,110, - 20,4,0,116,2,107,10,114,54,1,0,1,0,1,0,100, - 0,83,0,88,0,120,58,116,3,131,0,68,0,93,48,92, - 2,125,5,125,6,124,4,106,4,116,5,124,6,131,1,131, - 1,114,64,116,6,106,7,124,1,124,5,124,1,124,4,131, - 2,124,4,100,1,141,3,125,7,124,7,83,0,113,64,87, - 0,100,0,83,0,41,2,78,41,1,114,156,0,0,0,41, - 8,114,175,0,0,0,114,41,0,0,0,114,42,0,0,0, - 114,159,0,0,0,114,96,0,0,0,114,97,0,0,0,114, - 118,0,0,0,218,16,115,112,101,99,95,102,114,111,109,95, - 108,111,97,100,101,114,41,8,114,168,0,0,0,114,123,0, - 0,0,114,37,0,0,0,218,6,116,97,114,103,101,116,114, - 174,0,0,0,114,124,0,0,0,114,164,0,0,0,114,162, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,9,102,105,110,100,95,115,112,101,99,113,2,0, - 0,115,26,0,0,0,0,2,10,1,8,1,4,1,2,1, - 12,1,14,1,6,1,16,1,14,1,6,1,8,1,8,1, - 122,31,87,105,110,100,111,119,115,82,101,103,105,115,116,114, - 121,70,105,110,100,101,114,46,102,105,110,100,95,115,112,101, - 99,99,3,0,0,0,0,0,0,0,4,0,0,0,3,0, - 0,0,67,0,0,0,115,36,0,0,0,124,0,106,0,124, - 1,124,2,131,2,125,3,124,3,100,1,107,9,114,28,124, - 3,106,1,83,0,110,4,100,1,83,0,100,1,83,0,41, - 2,122,108,70,105,110,100,32,109,111,100,117,108,101,32,110, - 97,109,101,100,32,105,110,32,116,104,101,32,114,101,103,105, - 115,116,114,121,46,10,10,32,32,32,32,32,32,32,32,84, - 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, - 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,101, - 120,101,99,95,109,111,100,117,108,101,40,41,32,105,110,115, - 116,101,97,100,46,10,10,32,32,32,32,32,32,32,32,78, - 41,2,114,178,0,0,0,114,124,0,0,0,41,4,114,168, - 0,0,0,114,123,0,0,0,114,37,0,0,0,114,162,0, - 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,218,11,102,105,110,100,95,109,111,100,117,108,101,129,2, - 0,0,115,8,0,0,0,0,7,12,1,8,1,8,2,122, - 33,87,105,110,100,111,119,115,82,101,103,105,115,116,114,121, - 70,105,110,100,101,114,46,102,105,110,100,95,109,111,100,117, - 108,101,41,2,78,78,41,1,78,41,12,114,109,0,0,0, - 114,108,0,0,0,114,110,0,0,0,114,111,0,0,0,114, - 172,0,0,0,114,171,0,0,0,114,170,0,0,0,218,11, - 99,108,97,115,115,109,101,116,104,111,100,114,169,0,0,0, - 114,175,0,0,0,114,178,0,0,0,114,179,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,166,0,0,0,79,2,0,0,115,20,0,0, - 0,8,2,4,3,4,3,4,2,4,2,12,7,12,15,2, - 1,12,15,2,1,114,166,0,0,0,99,0,0,0,0,0, - 0,0,0,0,0,0,0,2,0,0,0,64,0,0,0,115, - 48,0,0,0,101,0,90,1,100,0,90,2,100,1,90,3, - 100,2,100,3,132,0,90,4,100,4,100,5,132,0,90,5, - 100,6,100,7,132,0,90,6,100,8,100,9,132,0,90,7, - 100,10,83,0,41,11,218,13,95,76,111,97,100,101,114,66, - 97,115,105,99,115,122,83,66,97,115,101,32,99,108,97,115, - 115,32,111,102,32,99,111,109,109,111,110,32,99,111,100,101, - 32,110,101,101,100,101,100,32,98,121,32,98,111,116,104,32, - 83,111,117,114,99,101,76,111,97,100,101,114,32,97,110,100, - 10,32,32,32,32,83,111,117,114,99,101,108,101,115,115,70, - 105,108,101,76,111,97,100,101,114,46,99,2,0,0,0,0, - 0,0,0,5,0,0,0,3,0,0,0,67,0,0,0,115, - 64,0,0,0,116,0,124,0,106,1,124,1,131,1,131,1, - 100,1,25,0,125,2,124,2,106,2,100,2,100,1,131,2, - 100,3,25,0,125,3,124,1,106,3,100,2,131,1,100,4, - 25,0,125,4,124,3,100,5,107,2,111,62,124,4,100,5, - 107,3,83,0,41,6,122,141,67,111,110,99,114,101,116,101, - 32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32, - 111,102,32,73,110,115,112,101,99,116,76,111,97,100,101,114, - 46,105,115,95,112,97,99,107,97,103,101,32,98,121,32,99, - 104,101,99,107,105,110,103,32,105,102,10,32,32,32,32,32, - 32,32,32,116,104,101,32,112,97,116,104,32,114,101,116,117, - 114,110,101,100,32,98,121,32,103,101,116,95,102,105,108,101, - 110,97,109,101,32,104,97,115,32,97,32,102,105,108,101,110, - 97,109,101,32,111,102,32,39,95,95,105,110,105,116,95,95, - 46,112,121,39,46,114,31,0,0,0,114,61,0,0,0,114, - 62,0,0,0,114,59,0,0,0,218,8,95,95,105,110,105, - 116,95,95,41,4,114,40,0,0,0,114,155,0,0,0,114, - 36,0,0,0,114,34,0,0,0,41,5,114,104,0,0,0, - 114,123,0,0,0,114,98,0,0,0,90,13,102,105,108,101, - 110,97,109,101,95,98,97,115,101,90,9,116,97,105,108,95, - 110,97,109,101,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,157,0,0,0,148,2,0,0,115,8,0,0, - 0,0,3,18,1,16,1,14,1,122,24,95,76,111,97,100, - 101,114,66,97,115,105,99,115,46,105,115,95,112,97,99,107, - 97,103,101,99,2,0,0,0,0,0,0,0,2,0,0,0, - 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, - 0,41,2,122,42,85,115,101,32,100,101,102,97,117,108,116, - 32,115,101,109,97,110,116,105,99,115,32,102,111,114,32,109, - 111,100,117,108,101,32,99,114,101,97,116,105,111,110,46,78, - 114,4,0,0,0,41,2,114,104,0,0,0,114,162,0,0, - 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 218,13,99,114,101,97,116,101,95,109,111,100,117,108,101,156, - 2,0,0,115,0,0,0,0,122,27,95,76,111,97,100,101, - 114,66,97,115,105,99,115,46,99,114,101,97,116,101,95,109, - 111,100,117,108,101,99,2,0,0,0,0,0,0,0,3,0, - 0,0,4,0,0,0,67,0,0,0,115,56,0,0,0,124, - 0,106,0,124,1,106,1,131,1,125,2,124,2,100,1,107, - 8,114,36,116,2,100,2,106,3,124,1,106,1,131,1,131, - 1,130,1,116,4,106,5,116,6,124,2,124,1,106,7,131, - 3,1,0,100,1,83,0,41,3,122,19,69,120,101,99,117, - 116,101,32,116,104,101,32,109,111,100,117,108,101,46,78,122, - 52,99,97,110,110,111,116,32,108,111,97,100,32,109,111,100, - 117,108,101,32,123,33,114,125,32,119,104,101,110,32,103,101, - 116,95,99,111,100,101,40,41,32,114,101,116,117,114,110,115, - 32,78,111,110,101,41,8,218,8,103,101,116,95,99,111,100, - 101,114,109,0,0,0,114,103,0,0,0,114,50,0,0,0, - 114,118,0,0,0,218,25,95,99,97,108,108,95,119,105,116, - 104,95,102,114,97,109,101,115,95,114,101,109,111,118,101,100, - 218,4,101,120,101,99,114,115,0,0,0,41,3,114,104,0, - 0,0,218,6,109,111,100,117,108,101,114,144,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,11, - 101,120,101,99,95,109,111,100,117,108,101,159,2,0,0,115, - 10,0,0,0,0,2,12,1,8,1,6,1,10,1,122,25, - 95,76,111,97,100,101,114,66,97,115,105,99,115,46,101,120, - 101,99,95,109,111,100,117,108,101,99,2,0,0,0,0,0, - 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,12, - 0,0,0,116,0,106,1,124,0,124,1,131,2,83,0,41, - 1,122,26,84,104,105,115,32,109,111,100,117,108,101,32,105, - 115,32,100,101,112,114,101,99,97,116,101,100,46,41,2,114, - 118,0,0,0,218,17,95,108,111,97,100,95,109,111,100,117, - 108,101,95,115,104,105,109,41,2,114,104,0,0,0,114,123, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,218,11,108,111,97,100,95,109,111,100,117,108,101,167, - 2,0,0,115,2,0,0,0,0,2,122,25,95,76,111,97, - 100,101,114,66,97,115,105,99,115,46,108,111,97,100,95,109, - 111,100,117,108,101,78,41,8,114,109,0,0,0,114,108,0, - 0,0,114,110,0,0,0,114,111,0,0,0,114,157,0,0, - 0,114,183,0,0,0,114,188,0,0,0,114,190,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,181,0,0,0,143,2,0,0,115,10,0, - 0,0,8,3,4,2,8,8,8,3,8,8,114,181,0,0, - 0,99,0,0,0,0,0,0,0,0,0,0,0,0,3,0, - 0,0,64,0,0,0,115,74,0,0,0,101,0,90,1,100, - 0,90,2,100,1,100,2,132,0,90,3,100,3,100,4,132, - 0,90,4,100,5,100,6,132,0,90,5,100,7,100,8,132, - 0,90,6,100,9,100,10,132,0,90,7,100,18,100,12,156, - 1,100,13,100,14,132,2,90,8,100,15,100,16,132,0,90, - 9,100,17,83,0,41,19,218,12,83,111,117,114,99,101,76, - 111,97,100,101,114,99,2,0,0,0,0,0,0,0,2,0, - 0,0,1,0,0,0,67,0,0,0,115,8,0,0,0,116, - 0,130,1,100,1,83,0,41,2,122,178,79,112,116,105,111, - 110,97,108,32,109,101,116,104,111,100,32,116,104,97,116,32, - 114,101,116,117,114,110,115,32,116,104,101,32,109,111,100,105, - 102,105,99,97,116,105,111,110,32,116,105,109,101,32,40,97, - 110,32,105,110,116,41,32,102,111,114,32,116,104,101,10,32, - 32,32,32,32,32,32,32,115,112,101,99,105,102,105,101,100, - 32,112,97,116,104,44,32,119,104,101,114,101,32,112,97,116, - 104,32,105,115,32,97,32,115,116,114,46,10,10,32,32,32, - 32,32,32,32,32,82,97,105,115,101,115,32,73,79,69,114, - 114,111,114,32,119,104,101,110,32,116,104,101,32,112,97,116, - 104,32,99,97,110,110,111,116,32,98,101,32,104,97,110,100, - 108,101,100,46,10,32,32,32,32,32,32,32,32,78,41,1, - 218,7,73,79,69,114,114,111,114,41,2,114,104,0,0,0, - 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,10,112,97,116,104,95,109,116,105,109,101, - 174,2,0,0,115,2,0,0,0,0,6,122,23,83,111,117, - 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,109, - 116,105,109,101,99,2,0,0,0,0,0,0,0,2,0,0, - 0,3,0,0,0,67,0,0,0,115,14,0,0,0,100,1, - 124,0,106,0,124,1,131,1,105,1,83,0,41,2,97,170, - 1,0,0,79,112,116,105,111,110,97,108,32,109,101,116,104, - 111,100,32,114,101,116,117,114,110,105,110,103,32,97,32,109, - 101,116,97,100,97,116,97,32,100,105,99,116,32,102,111,114, - 32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,112, - 97,116,104,10,32,32,32,32,32,32,32,32,116,111,32,98, - 121,32,116,104,101,32,112,97,116,104,32,40,115,116,114,41, - 46,10,32,32,32,32,32,32,32,32,80,111,115,115,105,98, - 108,101,32,107,101,121,115,58,10,32,32,32,32,32,32,32, - 32,45,32,39,109,116,105,109,101,39,32,40,109,97,110,100, - 97,116,111,114,121,41,32,105,115,32,116,104,101,32,110,117, - 109,101,114,105,99,32,116,105,109,101,115,116,97,109,112,32, - 111,102,32,108,97,115,116,32,115,111,117,114,99,101,10,32, - 32,32,32,32,32,32,32,32,32,99,111,100,101,32,109,111, - 100,105,102,105,99,97,116,105,111,110,59,10,32,32,32,32, - 32,32,32,32,45,32,39,115,105,122,101,39,32,40,111,112, - 116,105,111,110,97,108,41,32,105,115,32,116,104,101,32,115, - 105,122,101,32,105,110,32,98,121,116,101,115,32,111,102,32, - 116,104,101,32,115,111,117,114,99,101,32,99,111,100,101,46, - 10,10,32,32,32,32,32,32,32,32,73,109,112,108,101,109, - 101,110,116,105,110,103,32,116,104,105,115,32,109,101,116,104, - 111,100,32,97,108,108,111,119,115,32,116,104,101,32,108,111, - 97,100,101,114,32,116,111,32,114,101,97,100,32,98,121,116, - 101,99,111,100,101,32,102,105,108,101,115,46,10,32,32,32, - 32,32,32,32,32,82,97,105,115,101,115,32,73,79,69,114, - 114,111,114,32,119,104,101,110,32,116,104,101,32,112,97,116, - 104,32,99,97,110,110,111,116,32,98,101,32,104,97,110,100, - 108,101,100,46,10,32,32,32,32,32,32,32,32,114,130,0, - 0,0,41,1,114,193,0,0,0,41,2,114,104,0,0,0, - 114,37,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,10,112,97,116,104,95,115,116,97,116,115, - 182,2,0,0,115,2,0,0,0,0,11,122,23,83,111,117, - 114,99,101,76,111,97,100,101,114,46,112,97,116,104,95,115, - 116,97,116,115,99,4,0,0,0,0,0,0,0,4,0,0, - 0,3,0,0,0,67,0,0,0,115,12,0,0,0,124,0, - 106,0,124,2,124,3,131,2,83,0,41,1,122,228,79,112, - 116,105,111,110,97,108,32,109,101,116,104,111,100,32,119,104, - 105,99,104,32,119,114,105,116,101,115,32,100,97,116,97,32, - 40,98,121,116,101,115,41,32,116,111,32,97,32,102,105,108, - 101,32,112,97,116,104,32,40,97,32,115,116,114,41,46,10, - 10,32,32,32,32,32,32,32,32,73,109,112,108,101,109,101, - 110,116,105,110,103,32,116,104,105,115,32,109,101,116,104,111, - 100,32,97,108,108,111,119,115,32,102,111,114,32,116,104,101, - 32,119,114,105,116,105,110,103,32,111,102,32,98,121,116,101, - 99,111,100,101,32,102,105,108,101,115,46,10,10,32,32,32, - 32,32,32,32,32,84,104,101,32,115,111,117,114,99,101,32, - 112,97,116,104,32,105,115,32,110,101,101,100,101,100,32,105, - 110,32,111,114,100,101,114,32,116,111,32,99,111,114,114,101, - 99,116,108,121,32,116,114,97,110,115,102,101,114,32,112,101, - 114,109,105,115,115,105,111,110,115,10,32,32,32,32,32,32, - 32,32,41,1,218,8,115,101,116,95,100,97,116,97,41,4, - 114,104,0,0,0,114,94,0,0,0,90,10,99,97,99,104, - 101,95,112,97,116,104,114,56,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,218,15,95,99,97,99, - 104,101,95,98,121,116,101,99,111,100,101,195,2,0,0,115, - 2,0,0,0,0,8,122,28,83,111,117,114,99,101,76,111, - 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, - 99,111,100,101,99,3,0,0,0,0,0,0,0,3,0,0, - 0,1,0,0,0,67,0,0,0,115,4,0,0,0,100,1, - 83,0,41,2,122,150,79,112,116,105,111,110,97,108,32,109, - 101,116,104,111,100,32,119,104,105,99,104,32,119,114,105,116, - 101,115,32,100,97,116,97,32,40,98,121,116,101,115,41,32, - 116,111,32,97,32,102,105,108,101,32,112,97,116,104,32,40, - 97,32,115,116,114,41,46,10,10,32,32,32,32,32,32,32, - 32,73,109,112,108,101,109,101,110,116,105,110,103,32,116,104, - 105,115,32,109,101,116,104,111,100,32,97,108,108,111,119,115, - 32,102,111,114,32,116,104,101,32,119,114,105,116,105,110,103, - 32,111,102,32,98,121,116,101,99,111,100,101,32,102,105,108, - 101,115,46,10,32,32,32,32,32,32,32,32,78,114,4,0, - 0,0,41,3,114,104,0,0,0,114,37,0,0,0,114,56, - 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,195,0,0,0,205,2,0,0,115,0,0,0,0, - 122,21,83,111,117,114,99,101,76,111,97,100,101,114,46,115, - 101,116,95,100,97,116,97,99,2,0,0,0,0,0,0,0, - 5,0,0,0,16,0,0,0,67,0,0,0,115,82,0,0, - 0,124,0,106,0,124,1,131,1,125,2,121,14,124,0,106, - 1,124,2,131,1,125,3,87,0,110,48,4,0,116,2,107, - 10,114,72,1,0,125,4,1,0,122,20,116,3,100,1,124, - 1,100,2,141,2,124,4,130,2,87,0,89,0,100,3,100, - 3,125,4,126,4,88,0,110,2,88,0,116,4,124,3,131, - 1,83,0,41,4,122,52,67,111,110,99,114,101,116,101,32, - 105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111, - 102,32,73,110,115,112,101,99,116,76,111,97,100,101,114,46, - 103,101,116,95,115,111,117,114,99,101,46,122,39,115,111,117, - 114,99,101,32,110,111,116,32,97,118,97,105,108,97,98,108, - 101,32,116,104,114,111,117,103,104,32,103,101,116,95,100,97, - 116,97,40,41,41,1,114,102,0,0,0,78,41,5,114,155, - 0,0,0,218,8,103,101,116,95,100,97,116,97,114,42,0, - 0,0,114,103,0,0,0,114,153,0,0,0,41,5,114,104, - 0,0,0,114,123,0,0,0,114,37,0,0,0,114,151,0, - 0,0,218,3,101,120,99,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,10,103,101,116,95,115,111,117,114, - 99,101,212,2,0,0,115,14,0,0,0,0,2,10,1,2, - 1,14,1,16,1,4,1,28,1,122,23,83,111,117,114,99, - 101,76,111,97,100,101,114,46,103,101,116,95,115,111,117,114, - 99,101,114,31,0,0,0,41,1,218,9,95,111,112,116,105, - 109,105,122,101,99,3,0,0,0,1,0,0,0,4,0,0, - 0,8,0,0,0,67,0,0,0,115,22,0,0,0,116,0, - 106,1,116,2,124,1,124,2,100,1,100,2,124,3,100,3, - 141,6,83,0,41,4,122,130,82,101,116,117,114,110,32,116, - 104,101,32,99,111,100,101,32,111,98,106,101,99,116,32,99, - 111,109,112,105,108,101,100,32,102,114,111,109,32,115,111,117, - 114,99,101,46,10,10,32,32,32,32,32,32,32,32,84,104, - 101,32,39,100,97,116,97,39,32,97,114,103,117,109,101,110, - 116,32,99,97,110,32,98,101,32,97,110,121,32,111,98,106, - 101,99,116,32,116,121,112,101,32,116,104,97,116,32,99,111, - 109,112,105,108,101,40,41,32,115,117,112,112,111,114,116,115, - 46,10,32,32,32,32,32,32,32,32,114,186,0,0,0,84, - 41,2,218,12,100,111,110,116,95,105,110,104,101,114,105,116, - 114,72,0,0,0,41,3,114,118,0,0,0,114,185,0,0, - 0,218,7,99,111,109,112,105,108,101,41,4,114,104,0,0, - 0,114,56,0,0,0,114,37,0,0,0,114,200,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, - 14,115,111,117,114,99,101,95,116,111,95,99,111,100,101,222, - 2,0,0,115,4,0,0,0,0,5,12,1,122,27,83,111, - 117,114,99,101,76,111,97,100,101,114,46,115,111,117,114,99, - 101,95,116,111,95,99,111,100,101,99,2,0,0,0,0,0, - 0,0,10,0,0,0,43,0,0,0,67,0,0,0,115,94, - 1,0,0,124,0,106,0,124,1,131,1,125,2,100,1,125, - 3,121,12,116,1,124,2,131,1,125,4,87,0,110,24,4, - 0,116,2,107,10,114,50,1,0,1,0,1,0,100,1,125, - 4,89,0,110,162,88,0,121,14,124,0,106,3,124,2,131, - 1,125,5,87,0,110,20,4,0,116,4,107,10,114,86,1, - 0,1,0,1,0,89,0,110,126,88,0,116,5,124,5,100, - 2,25,0,131,1,125,3,121,14,124,0,106,6,124,4,131, - 1,125,6,87,0,110,20,4,0,116,7,107,10,114,134,1, - 0,1,0,1,0,89,0,110,78,88,0,121,20,116,8,124, - 6,124,5,124,1,124,4,100,3,141,4,125,7,87,0,110, - 24,4,0,116,9,116,10,102,2,107,10,114,180,1,0,1, - 0,1,0,89,0,110,32,88,0,116,11,106,12,100,4,124, - 4,124,2,131,3,1,0,116,13,124,7,124,1,124,4,124, - 2,100,5,141,4,83,0,124,0,106,6,124,2,131,1,125, - 8,124,0,106,14,124,8,124,2,131,2,125,9,116,11,106, - 12,100,6,124,2,131,2,1,0,116,15,106,16,12,0,144, - 1,114,90,124,4,100,1,107,9,144,1,114,90,124,3,100, - 1,107,9,144,1,114,90,116,17,124,9,124,3,116,18,124, - 8,131,1,131,3,125,6,121,30,124,0,106,19,124,2,124, - 4,124,6,131,3,1,0,116,11,106,12,100,7,124,4,131, - 2,1,0,87,0,110,22,4,0,116,2,107,10,144,1,114, - 88,1,0,1,0,1,0,89,0,110,2,88,0,124,9,83, - 0,41,8,122,190,67,111,110,99,114,101,116,101,32,105,109, - 112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32, - 73,110,115,112,101,99,116,76,111,97,100,101,114,46,103,101, - 116,95,99,111,100,101,46,10,10,32,32,32,32,32,32,32, - 32,82,101,97,100,105,110,103,32,111,102,32,98,121,116,101, - 99,111,100,101,32,114,101,113,117,105,114,101,115,32,112,97, - 116,104,95,115,116,97,116,115,32,116,111,32,98,101,32,105, - 109,112,108,101,109,101,110,116,101,100,46,32,84,111,32,119, - 114,105,116,101,10,32,32,32,32,32,32,32,32,98,121,116, - 101,99,111,100,101,44,32,115,101,116,95,100,97,116,97,32, - 109,117,115,116,32,97,108,115,111,32,98,101,32,105,109,112, - 108,101,109,101,110,116,101,100,46,10,10,32,32,32,32,32, - 32,32,32,78,114,130,0,0,0,41,3,114,136,0,0,0, - 114,102,0,0,0,114,37,0,0,0,122,13,123,125,32,109, - 97,116,99,104,101,115,32,123,125,41,3,114,102,0,0,0, - 114,93,0,0,0,114,94,0,0,0,122,19,99,111,100,101, - 32,111,98,106,101,99,116,32,102,114,111,109,32,123,125,122, - 10,119,114,111,116,101,32,123,33,114,125,41,20,114,155,0, - 0,0,114,83,0,0,0,114,70,0,0,0,114,194,0,0, - 0,114,192,0,0,0,114,16,0,0,0,114,197,0,0,0, - 114,42,0,0,0,114,139,0,0,0,114,103,0,0,0,114, - 134,0,0,0,114,118,0,0,0,114,133,0,0,0,114,145, - 0,0,0,114,203,0,0,0,114,8,0,0,0,218,19,100, - 111,110,116,95,119,114,105,116,101,95,98,121,116,101,99,111, - 100,101,114,148,0,0,0,114,33,0,0,0,114,196,0,0, - 0,41,10,114,104,0,0,0,114,123,0,0,0,114,94,0, - 0,0,114,137,0,0,0,114,93,0,0,0,218,2,115,116, - 114,56,0,0,0,218,10,98,121,116,101,115,95,100,97,116, - 97,114,151,0,0,0,90,11,99,111,100,101,95,111,98,106, - 101,99,116,114,4,0,0,0,114,4,0,0,0,114,6,0, - 0,0,114,184,0,0,0,230,2,0,0,115,78,0,0,0, - 0,7,10,1,4,1,2,1,12,1,14,1,10,2,2,1, - 14,1,14,1,6,2,12,1,2,1,14,1,14,1,6,2, - 2,1,4,1,4,1,12,1,18,1,6,2,8,1,6,1, - 6,1,2,1,8,1,10,1,12,1,12,1,20,1,10,1, - 6,1,10,1,2,1,14,1,16,1,16,1,6,1,122,21, - 83,111,117,114,99,101,76,111,97,100,101,114,46,103,101,116, - 95,99,111,100,101,78,114,91,0,0,0,41,10,114,109,0, - 0,0,114,108,0,0,0,114,110,0,0,0,114,193,0,0, - 0,114,194,0,0,0,114,196,0,0,0,114,195,0,0,0, - 114,199,0,0,0,114,203,0,0,0,114,184,0,0,0,114, - 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,191,0,0,0,172,2,0,0,115,14,0,0, - 0,8,2,8,8,8,13,8,10,8,7,8,10,14,8,114, - 191,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, - 0,4,0,0,0,0,0,0,0,115,80,0,0,0,101,0, + 100,101,114,46,102,105,110,100,95,115,112,101,99,99,3,0, + 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0, + 0,0,115,34,0,0,0,124,0,106,0,124,1,124,2,131, + 2,125,3,124,3,100,1,107,9,114,26,124,3,106,1,83, + 0,100,1,83,0,100,1,83,0,41,2,122,108,70,105,110, + 100,32,109,111,100,117,108,101,32,110,97,109,101,100,32,105, + 110,32,116,104,101,32,114,101,103,105,115,116,114,121,46,10, + 10,32,32,32,32,32,32,32,32,84,104,105,115,32,109,101, + 116,104,111,100,32,105,115,32,100,101,112,114,101,99,97,116, + 101,100,46,32,32,85,115,101,32,101,120,101,99,95,109,111, + 100,117,108,101,40,41,32,105,110,115,116,101,97,100,46,10, + 10,32,32,32,32,32,32,32,32,78,41,2,114,178,0,0, + 0,114,124,0,0,0,41,4,114,168,0,0,0,114,123,0, + 0,0,114,37,0,0,0,114,162,0,0,0,114,4,0,0, + 0,114,4,0,0,0,114,6,0,0,0,218,11,102,105,110, + 100,95,109,111,100,117,108,101,129,2,0,0,115,8,0,0, + 0,0,7,12,1,8,1,6,2,122,33,87,105,110,100,111, + 119,115,82,101,103,105,115,116,114,121,70,105,110,100,101,114, + 46,102,105,110,100,95,109,111,100,117,108,101,41,2,78,78, + 41,1,78,41,12,114,109,0,0,0,114,108,0,0,0,114, + 110,0,0,0,114,111,0,0,0,114,172,0,0,0,114,171, + 0,0,0,114,170,0,0,0,218,11,99,108,97,115,115,109, + 101,116,104,111,100,114,169,0,0,0,114,175,0,0,0,114, + 178,0,0,0,114,179,0,0,0,114,4,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,166,0, + 0,0,79,2,0,0,115,20,0,0,0,8,2,4,3,4, + 3,4,2,4,2,12,7,12,15,2,1,12,15,2,1,114, + 166,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, + 0,2,0,0,0,64,0,0,0,115,48,0,0,0,101,0, 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0, 90,4,100,4,100,5,132,0,90,5,100,6,100,7,132,0, - 90,6,101,7,135,0,102,1,100,8,100,9,132,8,131,1, - 90,8,101,7,100,10,100,11,132,0,131,1,90,9,100,12, - 100,13,132,0,90,10,135,0,90,11,100,14,83,0,41,15, - 218,10,70,105,108,101,76,111,97,100,101,114,122,103,66,97, - 115,101,32,102,105,108,101,32,108,111,97,100,101,114,32,99, - 108,97,115,115,32,119,104,105,99,104,32,105,109,112,108,101, - 109,101,110,116,115,32,116,104,101,32,108,111,97,100,101,114, - 32,112,114,111,116,111,99,111,108,32,109,101,116,104,111,100, - 115,32,116,104,97,116,10,32,32,32,32,114,101,113,117,105, - 114,101,32,102,105,108,101,32,115,121,115,116,101,109,32,117, - 115,97,103,101,46,99,3,0,0,0,0,0,0,0,3,0, - 0,0,2,0,0,0,67,0,0,0,115,16,0,0,0,124, - 1,124,0,95,0,124,2,124,0,95,1,100,1,83,0,41, - 2,122,75,67,97,99,104,101,32,116,104,101,32,109,111,100, - 117,108,101,32,110,97,109,101,32,97,110,100,32,116,104,101, - 32,112,97,116,104,32,116,111,32,116,104,101,32,102,105,108, - 101,32,102,111,117,110,100,32,98,121,32,116,104,101,10,32, - 32,32,32,32,32,32,32,102,105,110,100,101,114,46,78,41, - 2,114,102,0,0,0,114,37,0,0,0,41,3,114,104,0, - 0,0,114,123,0,0,0,114,37,0,0,0,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,114,182,0,0,0, - 31,3,0,0,115,4,0,0,0,0,3,6,1,122,19,70, - 105,108,101,76,111,97,100,101,114,46,95,95,105,110,105,116, - 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, - 0,0,0,67,0,0,0,115,24,0,0,0,124,0,106,0, - 124,1,106,0,107,2,111,22,124,0,106,1,124,1,106,1, - 107,2,83,0,41,1,78,41,2,218,9,95,95,99,108,97, - 115,115,95,95,114,115,0,0,0,41,2,114,104,0,0,0, - 218,5,111,116,104,101,114,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,6,95,95,101,113,95,95,37,3, - 0,0,115,4,0,0,0,0,1,12,1,122,17,70,105,108, - 101,76,111,97,100,101,114,46,95,95,101,113,95,95,99,1, - 0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,67, - 0,0,0,115,20,0,0,0,116,0,124,0,106,1,131,1, - 116,0,124,0,106,2,131,1,65,0,83,0,41,1,78,41, - 3,218,4,104,97,115,104,114,102,0,0,0,114,37,0,0, - 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,218,8,95,95,104,97,115,104,95, - 95,41,3,0,0,115,2,0,0,0,0,1,122,19,70,105, - 108,101,76,111,97,100,101,114,46,95,95,104,97,115,104,95, - 95,99,2,0,0,0,0,0,0,0,2,0,0,0,3,0, - 0,0,3,0,0,0,115,16,0,0,0,116,0,116,1,124, - 0,131,2,106,2,124,1,131,1,83,0,41,1,122,100,76, - 111,97,100,32,97,32,109,111,100,117,108,101,32,102,114,111, - 109,32,97,32,102,105,108,101,46,10,10,32,32,32,32,32, - 32,32,32,84,104,105,115,32,109,101,116,104,111,100,32,105, - 115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,85, - 115,101,32,101,120,101,99,95,109,111,100,117,108,101,40,41, - 32,105,110,115,116,101,97,100,46,10,10,32,32,32,32,32, - 32,32,32,41,3,218,5,115,117,112,101,114,114,207,0,0, - 0,114,190,0,0,0,41,2,114,104,0,0,0,114,123,0, - 0,0,41,1,114,208,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,190,0,0,0,44,3,0,0,115,2,0,0, - 0,0,10,122,22,70,105,108,101,76,111,97,100,101,114,46, - 108,111,97,100,95,109,111,100,117,108,101,99,2,0,0,0, - 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, - 115,6,0,0,0,124,0,106,0,83,0,41,1,122,58,82, - 101,116,117,114,110,32,116,104,101,32,112,97,116,104,32,116, - 111,32,116,104,101,32,115,111,117,114,99,101,32,102,105,108, - 101,32,97,115,32,102,111,117,110,100,32,98,121,32,116,104, - 101,32,102,105,110,100,101,114,46,41,1,114,37,0,0,0, + 90,6,100,8,100,9,132,0,90,7,100,10,83,0,41,11, + 218,13,95,76,111,97,100,101,114,66,97,115,105,99,115,122, + 83,66,97,115,101,32,99,108,97,115,115,32,111,102,32,99, + 111,109,109,111,110,32,99,111,100,101,32,110,101,101,100,101, + 100,32,98,121,32,98,111,116,104,32,83,111,117,114,99,101, + 76,111,97,100,101,114,32,97,110,100,10,32,32,32,32,83, + 111,117,114,99,101,108,101,115,115,70,105,108,101,76,111,97, + 100,101,114,46,99,2,0,0,0,0,0,0,0,5,0,0, + 0,3,0,0,0,67,0,0,0,115,64,0,0,0,116,0, + 124,0,106,1,124,1,131,1,131,1,100,1,25,0,125,2, + 124,2,106,2,100,2,100,1,131,2,100,3,25,0,125,3, + 124,1,106,3,100,2,131,1,100,4,25,0,125,4,124,3, + 100,5,107,2,111,62,124,4,100,5,107,3,83,0,41,6, + 122,141,67,111,110,99,114,101,116,101,32,105,109,112,108,101, + 109,101,110,116,97,116,105,111,110,32,111,102,32,73,110,115, + 112,101,99,116,76,111,97,100,101,114,46,105,115,95,112,97, + 99,107,97,103,101,32,98,121,32,99,104,101,99,107,105,110, + 103,32,105,102,10,32,32,32,32,32,32,32,32,116,104,101, + 32,112,97,116,104,32,114,101,116,117,114,110,101,100,32,98, + 121,32,103,101,116,95,102,105,108,101,110,97,109,101,32,104, + 97,115,32,97,32,102,105,108,101,110,97,109,101,32,111,102, + 32,39,95,95,105,110,105,116,95,95,46,112,121,39,46,114, + 31,0,0,0,114,61,0,0,0,114,62,0,0,0,114,59, + 0,0,0,218,8,95,95,105,110,105,116,95,95,41,4,114, + 40,0,0,0,114,155,0,0,0,114,36,0,0,0,114,34, + 0,0,0,41,5,114,104,0,0,0,114,123,0,0,0,114, + 98,0,0,0,90,13,102,105,108,101,110,97,109,101,95,98, + 97,115,101,90,9,116,97,105,108,95,110,97,109,101,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,157,0, + 0,0,148,2,0,0,115,8,0,0,0,0,3,18,1,16, + 1,14,1,122,24,95,76,111,97,100,101,114,66,97,115,105, + 99,115,46,105,115,95,112,97,99,107,97,103,101,99,2,0, + 0,0,0,0,0,0,2,0,0,0,1,0,0,0,67,0, + 0,0,115,4,0,0,0,100,1,83,0,41,2,122,42,85, + 115,101,32,100,101,102,97,117,108,116,32,115,101,109,97,110, + 116,105,99,115,32,102,111,114,32,109,111,100,117,108,101,32, + 99,114,101,97,116,105,111,110,46,78,114,4,0,0,0,41, + 2,114,104,0,0,0,114,162,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,218,13,99,114,101,97, + 116,101,95,109,111,100,117,108,101,156,2,0,0,115,0,0, + 0,0,122,27,95,76,111,97,100,101,114,66,97,115,105,99, + 115,46,99,114,101,97,116,101,95,109,111,100,117,108,101,99, + 2,0,0,0,0,0,0,0,3,0,0,0,4,0,0,0, + 67,0,0,0,115,56,0,0,0,124,0,106,0,124,1,106, + 1,131,1,125,2,124,2,100,1,107,8,114,36,116,2,100, + 2,106,3,124,1,106,1,131,1,131,1,130,1,116,4,106, + 5,116,6,124,2,124,1,106,7,131,3,1,0,100,1,83, + 0,41,3,122,19,69,120,101,99,117,116,101,32,116,104,101, + 32,109,111,100,117,108,101,46,78,122,52,99,97,110,110,111, + 116,32,108,111,97,100,32,109,111,100,117,108,101,32,123,33, + 114,125,32,119,104,101,110,32,103,101,116,95,99,111,100,101, + 40,41,32,114,101,116,117,114,110,115,32,78,111,110,101,41, + 8,218,8,103,101,116,95,99,111,100,101,114,109,0,0,0, + 114,103,0,0,0,114,50,0,0,0,114,118,0,0,0,218, + 25,95,99,97,108,108,95,119,105,116,104,95,102,114,97,109, + 101,115,95,114,101,109,111,118,101,100,218,4,101,120,101,99, + 114,115,0,0,0,41,3,114,104,0,0,0,218,6,109,111, + 100,117,108,101,114,144,0,0,0,114,4,0,0,0,114,4, + 0,0,0,114,6,0,0,0,218,11,101,120,101,99,95,109, + 111,100,117,108,101,159,2,0,0,115,10,0,0,0,0,2, + 12,1,8,1,6,1,10,1,122,25,95,76,111,97,100,101, + 114,66,97,115,105,99,115,46,101,120,101,99,95,109,111,100, + 117,108,101,99,2,0,0,0,0,0,0,0,2,0,0,0, + 3,0,0,0,67,0,0,0,115,12,0,0,0,116,0,106, + 1,124,0,124,1,131,2,83,0,41,1,122,26,84,104,105, + 115,32,109,111,100,117,108,101,32,105,115,32,100,101,112,114, + 101,99,97,116,101,100,46,41,2,114,118,0,0,0,218,17, + 95,108,111,97,100,95,109,111,100,117,108,101,95,115,104,105, + 109,41,2,114,104,0,0,0,114,123,0,0,0,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,218,11,108,111, + 97,100,95,109,111,100,117,108,101,167,2,0,0,115,2,0, + 0,0,0,2,122,25,95,76,111,97,100,101,114,66,97,115, + 105,99,115,46,108,111,97,100,95,109,111,100,117,108,101,78, + 41,8,114,109,0,0,0,114,108,0,0,0,114,110,0,0, + 0,114,111,0,0,0,114,157,0,0,0,114,183,0,0,0, + 114,188,0,0,0,114,190,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,114,181, + 0,0,0,143,2,0,0,115,10,0,0,0,8,3,4,2, + 8,8,8,3,8,8,114,181,0,0,0,99,0,0,0,0, + 0,0,0,0,0,0,0,0,3,0,0,0,64,0,0,0, + 115,74,0,0,0,101,0,90,1,100,0,90,2,100,1,100, + 2,132,0,90,3,100,3,100,4,132,0,90,4,100,5,100, + 6,132,0,90,5,100,7,100,8,132,0,90,6,100,9,100, + 10,132,0,90,7,100,18,100,12,156,1,100,13,100,14,132, + 2,90,8,100,15,100,16,132,0,90,9,100,17,83,0,41, + 19,218,12,83,111,117,114,99,101,76,111,97,100,101,114,99, + 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, + 67,0,0,0,115,8,0,0,0,116,0,130,1,100,1,83, + 0,41,2,122,178,79,112,116,105,111,110,97,108,32,109,101, + 116,104,111,100,32,116,104,97,116,32,114,101,116,117,114,110, + 115,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105, + 111,110,32,116,105,109,101,32,40,97,110,32,105,110,116,41, + 32,102,111,114,32,116,104,101,10,32,32,32,32,32,32,32, + 32,115,112,101,99,105,102,105,101,100,32,112,97,116,104,44, + 32,119,104,101,114,101,32,112,97,116,104,32,105,115,32,97, + 32,115,116,114,46,10,10,32,32,32,32,32,32,32,32,82, + 97,105,115,101,115,32,73,79,69,114,114,111,114,32,119,104, + 101,110,32,116,104,101,32,112,97,116,104,32,99,97,110,110, + 111,116,32,98,101,32,104,97,110,100,108,101,100,46,10,32, + 32,32,32,32,32,32,32,78,41,1,218,7,73,79,69,114, + 114,111,114,41,2,114,104,0,0,0,114,37,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,10, + 112,97,116,104,95,109,116,105,109,101,174,2,0,0,115,2, + 0,0,0,0,6,122,23,83,111,117,114,99,101,76,111,97, + 100,101,114,46,112,97,116,104,95,109,116,105,109,101,99,2, + 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67, + 0,0,0,115,14,0,0,0,100,1,124,0,106,0,124,1, + 131,1,105,1,83,0,41,2,97,170,1,0,0,79,112,116, + 105,111,110,97,108,32,109,101,116,104,111,100,32,114,101,116, + 117,114,110,105,110,103,32,97,32,109,101,116,97,100,97,116, + 97,32,100,105,99,116,32,102,111,114,32,116,104,101,32,115, + 112,101,99,105,102,105,101,100,32,112,97,116,104,10,32,32, + 32,32,32,32,32,32,116,111,32,98,121,32,116,104,101,32, + 112,97,116,104,32,40,115,116,114,41,46,10,32,32,32,32, + 32,32,32,32,80,111,115,115,105,98,108,101,32,107,101,121, + 115,58,10,32,32,32,32,32,32,32,32,45,32,39,109,116, + 105,109,101,39,32,40,109,97,110,100,97,116,111,114,121,41, + 32,105,115,32,116,104,101,32,110,117,109,101,114,105,99,32, + 116,105,109,101,115,116,97,109,112,32,111,102,32,108,97,115, + 116,32,115,111,117,114,99,101,10,32,32,32,32,32,32,32, + 32,32,32,99,111,100,101,32,109,111,100,105,102,105,99,97, + 116,105,111,110,59,10,32,32,32,32,32,32,32,32,45,32, + 39,115,105,122,101,39,32,40,111,112,116,105,111,110,97,108, + 41,32,105,115,32,116,104,101,32,115,105,122,101,32,105,110, + 32,98,121,116,101,115,32,111,102,32,116,104,101,32,115,111, + 117,114,99,101,32,99,111,100,101,46,10,10,32,32,32,32, + 32,32,32,32,73,109,112,108,101,109,101,110,116,105,110,103, + 32,116,104,105,115,32,109,101,116,104,111,100,32,97,108,108, + 111,119,115,32,116,104,101,32,108,111,97,100,101,114,32,116, + 111,32,114,101,97,100,32,98,121,116,101,99,111,100,101,32, + 102,105,108,101,115,46,10,32,32,32,32,32,32,32,32,82, + 97,105,115,101,115,32,73,79,69,114,114,111,114,32,119,104, + 101,110,32,116,104,101,32,112,97,116,104,32,99,97,110,110, + 111,116,32,98,101,32,104,97,110,100,108,101,100,46,10,32, + 32,32,32,32,32,32,32,114,130,0,0,0,41,1,114,193, + 0,0,0,41,2,114,104,0,0,0,114,37,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,10, + 112,97,116,104,95,115,116,97,116,115,182,2,0,0,115,2, + 0,0,0,0,11,122,23,83,111,117,114,99,101,76,111,97, + 100,101,114,46,112,97,116,104,95,115,116,97,116,115,99,4, + 0,0,0,0,0,0,0,4,0,0,0,3,0,0,0,67, + 0,0,0,115,12,0,0,0,124,0,106,0,124,2,124,3, + 131,2,83,0,41,1,122,228,79,112,116,105,111,110,97,108, + 32,109,101,116,104,111,100,32,119,104,105,99,104,32,119,114, + 105,116,101,115,32,100,97,116,97,32,40,98,121,116,101,115, + 41,32,116,111,32,97,32,102,105,108,101,32,112,97,116,104, + 32,40,97,32,115,116,114,41,46,10,10,32,32,32,32,32, + 32,32,32,73,109,112,108,101,109,101,110,116,105,110,103,32, + 116,104,105,115,32,109,101,116,104,111,100,32,97,108,108,111, + 119,115,32,102,111,114,32,116,104,101,32,119,114,105,116,105, + 110,103,32,111,102,32,98,121,116,101,99,111,100,101,32,102, + 105,108,101,115,46,10,10,32,32,32,32,32,32,32,32,84, + 104,101,32,115,111,117,114,99,101,32,112,97,116,104,32,105, + 115,32,110,101,101,100,101,100,32,105,110,32,111,114,100,101, + 114,32,116,111,32,99,111,114,114,101,99,116,108,121,32,116, + 114,97,110,115,102,101,114,32,112,101,114,109,105,115,115,105, + 111,110,115,10,32,32,32,32,32,32,32,32,41,1,218,8, + 115,101,116,95,100,97,116,97,41,4,114,104,0,0,0,114, + 94,0,0,0,90,10,99,97,99,104,101,95,112,97,116,104, + 114,56,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,218,15,95,99,97,99,104,101,95,98,121,116, + 101,99,111,100,101,195,2,0,0,115,2,0,0,0,0,8, + 122,28,83,111,117,114,99,101,76,111,97,100,101,114,46,95, + 99,97,99,104,101,95,98,121,116,101,99,111,100,101,99,3, + 0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,67, + 0,0,0,115,4,0,0,0,100,1,83,0,41,2,122,150, + 79,112,116,105,111,110,97,108,32,109,101,116,104,111,100,32, + 119,104,105,99,104,32,119,114,105,116,101,115,32,100,97,116, + 97,32,40,98,121,116,101,115,41,32,116,111,32,97,32,102, + 105,108,101,32,112,97,116,104,32,40,97,32,115,116,114,41, + 46,10,10,32,32,32,32,32,32,32,32,73,109,112,108,101, + 109,101,110,116,105,110,103,32,116,104,105,115,32,109,101,116, + 104,111,100,32,97,108,108,111,119,115,32,102,111,114,32,116, + 104,101,32,119,114,105,116,105,110,103,32,111,102,32,98,121, + 116,101,99,111,100,101,32,102,105,108,101,115,46,10,32,32, + 32,32,32,32,32,32,78,114,4,0,0,0,41,3,114,104, + 0,0,0,114,37,0,0,0,114,56,0,0,0,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,114,195,0,0, + 0,205,2,0,0,115,0,0,0,0,122,21,83,111,117,114, + 99,101,76,111,97,100,101,114,46,115,101,116,95,100,97,116, + 97,99,2,0,0,0,0,0,0,0,5,0,0,0,16,0, + 0,0,67,0,0,0,115,82,0,0,0,124,0,106,0,124, + 1,131,1,125,2,121,14,124,0,106,1,124,2,131,1,125, + 3,87,0,110,48,4,0,116,2,107,10,114,72,1,0,125, + 4,1,0,122,20,116,3,100,1,124,1,100,2,141,2,124, + 4,130,2,87,0,89,0,100,3,100,3,125,4,126,4,88, + 0,110,2,88,0,116,4,124,3,131,1,83,0,41,4,122, + 52,67,111,110,99,114,101,116,101,32,105,109,112,108,101,109, + 101,110,116,97,116,105,111,110,32,111,102,32,73,110,115,112, + 101,99,116,76,111,97,100,101,114,46,103,101,116,95,115,111, + 117,114,99,101,46,122,39,115,111,117,114,99,101,32,110,111, + 116,32,97,118,97,105,108,97,98,108,101,32,116,104,114,111, + 117,103,104,32,103,101,116,95,100,97,116,97,40,41,41,1, + 114,102,0,0,0,78,41,5,114,155,0,0,0,218,8,103, + 101,116,95,100,97,116,97,114,42,0,0,0,114,103,0,0, + 0,114,153,0,0,0,41,5,114,104,0,0,0,114,123,0, + 0,0,114,37,0,0,0,114,151,0,0,0,218,3,101,120, + 99,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,10,103,101,116,95,115,111,117,114,99,101,212,2,0,0, + 115,14,0,0,0,0,2,10,1,2,1,14,1,16,1,4, + 1,28,1,122,23,83,111,117,114,99,101,76,111,97,100,101, + 114,46,103,101,116,95,115,111,117,114,99,101,114,31,0,0, + 0,41,1,218,9,95,111,112,116,105,109,105,122,101,99,3, + 0,0,0,1,0,0,0,4,0,0,0,8,0,0,0,67, + 0,0,0,115,22,0,0,0,116,0,106,1,116,2,124,1, + 124,2,100,1,100,2,124,3,100,3,141,6,83,0,41,4, + 122,130,82,101,116,117,114,110,32,116,104,101,32,99,111,100, + 101,32,111,98,106,101,99,116,32,99,111,109,112,105,108,101, + 100,32,102,114,111,109,32,115,111,117,114,99,101,46,10,10, + 32,32,32,32,32,32,32,32,84,104,101,32,39,100,97,116, + 97,39,32,97,114,103,117,109,101,110,116,32,99,97,110,32, + 98,101,32,97,110,121,32,111,98,106,101,99,116,32,116,121, + 112,101,32,116,104,97,116,32,99,111,109,112,105,108,101,40, + 41,32,115,117,112,112,111,114,116,115,46,10,32,32,32,32, + 32,32,32,32,114,186,0,0,0,84,41,2,218,12,100,111, + 110,116,95,105,110,104,101,114,105,116,114,72,0,0,0,41, + 3,114,118,0,0,0,114,185,0,0,0,218,7,99,111,109, + 112,105,108,101,41,4,114,104,0,0,0,114,56,0,0,0, + 114,37,0,0,0,114,200,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,218,14,115,111,117,114,99, + 101,95,116,111,95,99,111,100,101,222,2,0,0,115,4,0, + 0,0,0,5,12,1,122,27,83,111,117,114,99,101,76,111, + 97,100,101,114,46,115,111,117,114,99,101,95,116,111,95,99, + 111,100,101,99,2,0,0,0,0,0,0,0,10,0,0,0, + 43,0,0,0,67,0,0,0,115,94,1,0,0,124,0,106, + 0,124,1,131,1,125,2,100,1,125,3,121,12,116,1,124, + 2,131,1,125,4,87,0,110,24,4,0,116,2,107,10,114, + 50,1,0,1,0,1,0,100,1,125,4,89,0,110,162,88, + 0,121,14,124,0,106,3,124,2,131,1,125,5,87,0,110, + 20,4,0,116,4,107,10,114,86,1,0,1,0,1,0,89, + 0,110,126,88,0,116,5,124,5,100,2,25,0,131,1,125, + 3,121,14,124,0,106,6,124,4,131,1,125,6,87,0,110, + 20,4,0,116,7,107,10,114,134,1,0,1,0,1,0,89, + 0,110,78,88,0,121,20,116,8,124,6,124,5,124,1,124, + 4,100,3,141,4,125,7,87,0,110,24,4,0,116,9,116, + 10,102,2,107,10,114,180,1,0,1,0,1,0,89,0,110, + 32,88,0,116,11,106,12,100,4,124,4,124,2,131,3,1, + 0,116,13,124,7,124,1,124,4,124,2,100,5,141,4,83, + 0,124,0,106,6,124,2,131,1,125,8,124,0,106,14,124, + 8,124,2,131,2,125,9,116,11,106,12,100,6,124,2,131, + 2,1,0,116,15,106,16,12,0,144,1,114,90,124,4,100, + 1,107,9,144,1,114,90,124,3,100,1,107,9,144,1,114, + 90,116,17,124,9,124,3,116,18,124,8,131,1,131,3,125, + 6,121,30,124,0,106,19,124,2,124,4,124,6,131,3,1, + 0,116,11,106,12,100,7,124,4,131,2,1,0,87,0,110, + 22,4,0,116,2,107,10,144,1,114,88,1,0,1,0,1, + 0,89,0,110,2,88,0,124,9,83,0,41,8,122,190,67, + 111,110,99,114,101,116,101,32,105,109,112,108,101,109,101,110, + 116,97,116,105,111,110,32,111,102,32,73,110,115,112,101,99, + 116,76,111,97,100,101,114,46,103,101,116,95,99,111,100,101, + 46,10,10,32,32,32,32,32,32,32,32,82,101,97,100,105, + 110,103,32,111,102,32,98,121,116,101,99,111,100,101,32,114, + 101,113,117,105,114,101,115,32,112,97,116,104,95,115,116,97, + 116,115,32,116,111,32,98,101,32,105,109,112,108,101,109,101, + 110,116,101,100,46,32,84,111,32,119,114,105,116,101,10,32, + 32,32,32,32,32,32,32,98,121,116,101,99,111,100,101,44, + 32,115,101,116,95,100,97,116,97,32,109,117,115,116,32,97, + 108,115,111,32,98,101,32,105,109,112,108,101,109,101,110,116, + 101,100,46,10,10,32,32,32,32,32,32,32,32,78,114,130, + 0,0,0,41,3,114,136,0,0,0,114,102,0,0,0,114, + 37,0,0,0,122,13,123,125,32,109,97,116,99,104,101,115, + 32,123,125,41,3,114,102,0,0,0,114,93,0,0,0,114, + 94,0,0,0,122,19,99,111,100,101,32,111,98,106,101,99, + 116,32,102,114,111,109,32,123,125,122,10,119,114,111,116,101, + 32,123,33,114,125,41,20,114,155,0,0,0,114,83,0,0, + 0,114,70,0,0,0,114,194,0,0,0,114,192,0,0,0, + 114,16,0,0,0,114,197,0,0,0,114,42,0,0,0,114, + 139,0,0,0,114,103,0,0,0,114,134,0,0,0,114,118, + 0,0,0,114,133,0,0,0,114,145,0,0,0,114,203,0, + 0,0,114,8,0,0,0,218,19,100,111,110,116,95,119,114, + 105,116,101,95,98,121,116,101,99,111,100,101,114,148,0,0, + 0,114,33,0,0,0,114,196,0,0,0,41,10,114,104,0, + 0,0,114,123,0,0,0,114,94,0,0,0,114,137,0,0, + 0,114,93,0,0,0,218,2,115,116,114,56,0,0,0,218, + 10,98,121,116,101,115,95,100,97,116,97,114,151,0,0,0, + 90,11,99,111,100,101,95,111,98,106,101,99,116,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,114,184,0,0, + 0,230,2,0,0,115,78,0,0,0,0,7,10,1,4,1, + 2,1,12,1,14,1,10,2,2,1,14,1,14,1,6,2, + 12,1,2,1,14,1,14,1,6,2,2,1,4,1,4,1, + 12,1,18,1,6,2,8,1,6,1,6,1,2,1,8,1, + 10,1,12,1,12,1,20,1,10,1,6,1,10,1,2,1, + 14,1,16,1,16,1,6,1,122,21,83,111,117,114,99,101, + 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,78, + 114,91,0,0,0,41,10,114,109,0,0,0,114,108,0,0, + 0,114,110,0,0,0,114,193,0,0,0,114,194,0,0,0, + 114,196,0,0,0,114,195,0,0,0,114,199,0,0,0,114, + 203,0,0,0,114,184,0,0,0,114,4,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,191,0, + 0,0,172,2,0,0,115,14,0,0,0,8,2,8,8,8, + 13,8,10,8,7,8,10,14,8,114,191,0,0,0,99,0, + 0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0, + 0,0,0,115,80,0,0,0,101,0,90,1,100,0,90,2, + 100,1,90,3,100,2,100,3,132,0,90,4,100,4,100,5, + 132,0,90,5,100,6,100,7,132,0,90,6,101,7,135,0, + 102,1,100,8,100,9,132,8,131,1,90,8,101,7,100,10, + 100,11,132,0,131,1,90,9,100,12,100,13,132,0,90,10, + 135,0,90,11,100,14,83,0,41,15,218,10,70,105,108,101, + 76,111,97,100,101,114,122,103,66,97,115,101,32,102,105,108, + 101,32,108,111,97,100,101,114,32,99,108,97,115,115,32,119, + 104,105,99,104,32,105,109,112,108,101,109,101,110,116,115,32, + 116,104,101,32,108,111,97,100,101,114,32,112,114,111,116,111, + 99,111,108,32,109,101,116,104,111,100,115,32,116,104,97,116, + 10,32,32,32,32,114,101,113,117,105,114,101,32,102,105,108, + 101,32,115,121,115,116,101,109,32,117,115,97,103,101,46,99, + 3,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0, + 67,0,0,0,115,16,0,0,0,124,1,124,0,95,0,124, + 2,124,0,95,1,100,1,83,0,41,2,122,75,67,97,99, + 104,101,32,116,104,101,32,109,111,100,117,108,101,32,110,97, + 109,101,32,97,110,100,32,116,104,101,32,112,97,116,104,32, + 116,111,32,116,104,101,32,102,105,108,101,32,102,111,117,110, + 100,32,98,121,32,116,104,101,10,32,32,32,32,32,32,32, + 32,102,105,110,100,101,114,46,78,41,2,114,102,0,0,0, + 114,37,0,0,0,41,3,114,104,0,0,0,114,123,0,0, + 0,114,37,0,0,0,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,114,182,0,0,0,31,3,0,0,115,4, + 0,0,0,0,3,6,1,122,19,70,105,108,101,76,111,97, + 100,101,114,46,95,95,105,110,105,116,95,95,99,2,0,0, + 0,0,0,0,0,2,0,0,0,2,0,0,0,67,0,0, + 0,115,24,0,0,0,124,0,106,0,124,1,106,0,107,2, + 111,22,124,0,106,1,124,1,106,1,107,2,83,0,41,1, + 78,41,2,218,9,95,95,99,108,97,115,115,95,95,114,115, + 0,0,0,41,2,114,104,0,0,0,218,5,111,116,104,101, + 114,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,6,95,95,101,113,95,95,37,3,0,0,115,4,0,0, + 0,0,1,12,1,122,17,70,105,108,101,76,111,97,100,101, + 114,46,95,95,101,113,95,95,99,1,0,0,0,0,0,0, + 0,1,0,0,0,3,0,0,0,67,0,0,0,115,20,0, + 0,0,116,0,124,0,106,1,131,1,116,0,124,0,106,2, + 131,1,65,0,83,0,41,1,78,41,3,218,4,104,97,115, + 104,114,102,0,0,0,114,37,0,0,0,41,1,114,104,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,218,8,95,95,104,97,115,104,95,95,41,3,0,0,115, + 2,0,0,0,0,1,122,19,70,105,108,101,76,111,97,100, + 101,114,46,95,95,104,97,115,104,95,95,99,2,0,0,0, + 0,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0, + 115,16,0,0,0,116,0,116,1,124,0,131,2,106,2,124, + 1,131,1,83,0,41,1,122,100,76,111,97,100,32,97,32, + 109,111,100,117,108,101,32,102,114,111,109,32,97,32,102,105, + 108,101,46,10,10,32,32,32,32,32,32,32,32,84,104,105, + 115,32,109,101,116,104,111,100,32,105,115,32,100,101,112,114, + 101,99,97,116,101,100,46,32,32,85,115,101,32,101,120,101, + 99,95,109,111,100,117,108,101,40,41,32,105,110,115,116,101, + 97,100,46,10,10,32,32,32,32,32,32,32,32,41,3,218, + 5,115,117,112,101,114,114,207,0,0,0,114,190,0,0,0, + 41,2,114,104,0,0,0,114,123,0,0,0,41,1,114,208, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,190,0, + 0,0,44,3,0,0,115,2,0,0,0,0,10,122,22,70, + 105,108,101,76,111,97,100,101,114,46,108,111,97,100,95,109, + 111,100,117,108,101,99,2,0,0,0,0,0,0,0,2,0, + 0,0,1,0,0,0,67,0,0,0,115,6,0,0,0,124, + 0,106,0,83,0,41,1,122,58,82,101,116,117,114,110,32, + 116,104,101,32,112,97,116,104,32,116,111,32,116,104,101,32, + 115,111,117,114,99,101,32,102,105,108,101,32,97,115,32,102, + 111,117,110,100,32,98,121,32,116,104,101,32,102,105,110,100, + 101,114,46,41,1,114,37,0,0,0,41,2,114,104,0,0, + 0,114,123,0,0,0,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,114,155,0,0,0,56,3,0,0,115,2, + 0,0,0,0,3,122,23,70,105,108,101,76,111,97,100,101, + 114,46,103,101,116,95,102,105,108,101,110,97,109,101,99,2, + 0,0,0,0,0,0,0,3,0,0,0,9,0,0,0,67, + 0,0,0,115,32,0,0,0,116,0,106,1,124,1,100,1, + 131,2,143,10,125,2,124,2,106,2,131,0,83,0,81,0, + 82,0,88,0,100,2,83,0,41,3,122,39,82,101,116,117, + 114,110,32,116,104,101,32,100,97,116,97,32,102,114,111,109, + 32,112,97,116,104,32,97,115,32,114,97,119,32,98,121,116, + 101,115,46,218,1,114,78,41,3,114,52,0,0,0,114,53, + 0,0,0,90,4,114,101,97,100,41,3,114,104,0,0,0, + 114,37,0,0,0,114,57,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,114,197,0,0,0,61,3, + 0,0,115,4,0,0,0,0,2,14,1,122,19,70,105,108, + 101,76,111,97,100,101,114,46,103,101,116,95,100,97,116,97, + 78,41,12,114,109,0,0,0,114,108,0,0,0,114,110,0, + 0,0,114,111,0,0,0,114,182,0,0,0,114,210,0,0, + 0,114,212,0,0,0,114,120,0,0,0,114,190,0,0,0, + 114,155,0,0,0,114,197,0,0,0,90,13,95,95,99,108, + 97,115,115,99,101,108,108,95,95,114,4,0,0,0,114,4, + 0,0,0,41,1,114,208,0,0,0,114,6,0,0,0,114, + 207,0,0,0,26,3,0,0,115,14,0,0,0,8,3,4, + 2,8,6,8,4,8,3,16,12,12,5,114,207,0,0,0, + 99,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0, + 0,64,0,0,0,115,46,0,0,0,101,0,90,1,100,0, + 90,2,100,1,90,3,100,2,100,3,132,0,90,4,100,4, + 100,5,132,0,90,5,100,6,100,7,156,1,100,8,100,9, + 132,2,90,6,100,10,83,0,41,11,218,16,83,111,117,114, + 99,101,70,105,108,101,76,111,97,100,101,114,122,62,67,111, + 110,99,114,101,116,101,32,105,109,112,108,101,109,101,110,116, + 97,116,105,111,110,32,111,102,32,83,111,117,114,99,101,76, + 111,97,100,101,114,32,117,115,105,110,103,32,116,104,101,32, + 102,105,108,101,32,115,121,115,116,101,109,46,99,2,0,0, + 0,0,0,0,0,3,0,0,0,3,0,0,0,67,0,0, + 0,115,22,0,0,0,116,0,124,1,131,1,125,2,124,2, + 106,1,124,2,106,2,100,1,156,2,83,0,41,2,122,33, + 82,101,116,117,114,110,32,116,104,101,32,109,101,116,97,100, + 97,116,97,32,102,111,114,32,116,104,101,32,112,97,116,104, + 46,41,2,114,130,0,0,0,114,131,0,0,0,41,3,114, + 41,0,0,0,218,8,115,116,95,109,116,105,109,101,90,7, + 115,116,95,115,105,122,101,41,3,114,104,0,0,0,114,37, + 0,0,0,114,205,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,194,0,0,0,71,3,0,0, + 115,4,0,0,0,0,2,8,1,122,27,83,111,117,114,99, + 101,70,105,108,101,76,111,97,100,101,114,46,112,97,116,104, + 95,115,116,97,116,115,99,4,0,0,0,0,0,0,0,5, + 0,0,0,5,0,0,0,67,0,0,0,115,24,0,0,0, + 116,0,124,1,131,1,125,4,124,0,106,1,124,2,124,3, + 124,4,100,1,141,3,83,0,41,2,78,41,1,218,5,95, + 109,111,100,101,41,2,114,101,0,0,0,114,195,0,0,0, + 41,5,114,104,0,0,0,114,94,0,0,0,114,93,0,0, + 0,114,56,0,0,0,114,44,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,196,0,0,0,76, + 3,0,0,115,4,0,0,0,0,2,8,1,122,32,83,111, + 117,114,99,101,70,105,108,101,76,111,97,100,101,114,46,95, + 99,97,99,104,101,95,98,121,116,101,99,111,100,101,105,182, + 1,0,0,41,1,114,217,0,0,0,99,3,0,0,0,1, + 0,0,0,9,0,0,0,17,0,0,0,67,0,0,0,115, + 250,0,0,0,116,0,124,1,131,1,92,2,125,4,125,5, + 103,0,125,6,120,40,124,4,114,56,116,1,124,4,131,1, + 12,0,114,56,116,0,124,4,131,1,92,2,125,4,125,7, + 124,6,106,2,124,7,131,1,1,0,113,18,87,0,120,108, + 116,3,124,6,131,1,68,0,93,96,125,7,116,4,124,4, + 124,7,131,2,125,4,121,14,116,5,106,6,124,4,131,1, + 1,0,87,0,113,68,4,0,116,7,107,10,114,118,1,0, + 1,0,1,0,119,68,89,0,113,68,4,0,116,8,107,10, + 114,162,1,0,125,8,1,0,122,18,116,9,106,10,100,1, + 124,4,124,8,131,3,1,0,100,2,83,0,100,2,125,8, + 126,8,88,0,113,68,88,0,113,68,87,0,121,28,116,11, + 124,1,124,2,124,3,131,3,1,0,116,9,106,10,100,3, + 124,1,131,2,1,0,87,0,110,48,4,0,116,8,107,10, + 114,244,1,0,125,8,1,0,122,20,116,9,106,10,100,1, + 124,1,124,8,131,3,1,0,87,0,89,0,100,2,100,2, + 125,8,126,8,88,0,110,2,88,0,100,2,83,0,41,4, + 122,27,87,114,105,116,101,32,98,121,116,101,115,32,100,97, + 116,97,32,116,111,32,97,32,102,105,108,101,46,122,27,99, + 111,117,108,100,32,110,111,116,32,99,114,101,97,116,101,32, + 123,33,114,125,58,32,123,33,114,125,78,122,12,99,114,101, + 97,116,101,100,32,123,33,114,125,41,12,114,40,0,0,0, + 114,48,0,0,0,114,161,0,0,0,114,35,0,0,0,114, + 30,0,0,0,114,3,0,0,0,90,5,109,107,100,105,114, + 218,15,70,105,108,101,69,120,105,115,116,115,69,114,114,111, + 114,114,42,0,0,0,114,118,0,0,0,114,133,0,0,0, + 114,58,0,0,0,41,9,114,104,0,0,0,114,37,0,0, + 0,114,56,0,0,0,114,217,0,0,0,218,6,112,97,114, + 101,110,116,114,98,0,0,0,114,29,0,0,0,114,25,0, + 0,0,114,198,0,0,0,114,4,0,0,0,114,4,0,0, + 0,114,6,0,0,0,114,195,0,0,0,81,3,0,0,115, + 42,0,0,0,0,2,12,1,4,2,16,1,12,1,14,2, + 14,1,10,1,2,1,14,1,14,2,6,1,16,3,6,1, + 8,1,20,1,2,1,12,1,16,1,16,2,8,1,122,25, + 83,111,117,114,99,101,70,105,108,101,76,111,97,100,101,114, + 46,115,101,116,95,100,97,116,97,78,41,7,114,109,0,0, + 0,114,108,0,0,0,114,110,0,0,0,114,111,0,0,0, + 114,194,0,0,0,114,196,0,0,0,114,195,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,114,215,0,0,0,67,3,0,0,115,8,0,0, + 0,8,2,4,2,8,5,8,5,114,215,0,0,0,99,0, + 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,64, + 0,0,0,115,32,0,0,0,101,0,90,1,100,0,90,2, + 100,1,90,3,100,2,100,3,132,0,90,4,100,4,100,5, + 132,0,90,5,100,6,83,0,41,7,218,20,83,111,117,114, + 99,101,108,101,115,115,70,105,108,101,76,111,97,100,101,114, + 122,45,76,111,97,100,101,114,32,119,104,105,99,104,32,104, + 97,110,100,108,101,115,32,115,111,117,114,99,101,108,101,115, + 115,32,102,105,108,101,32,105,109,112,111,114,116,115,46,99, + 2,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0, + 67,0,0,0,115,48,0,0,0,124,0,106,0,124,1,131, + 1,125,2,124,0,106,1,124,2,131,1,125,3,116,2,124, + 3,124,1,124,2,100,1,141,3,125,4,116,3,124,4,124, + 1,124,2,100,2,141,3,83,0,41,3,78,41,2,114,102, + 0,0,0,114,37,0,0,0,41,2,114,102,0,0,0,114, + 93,0,0,0,41,4,114,155,0,0,0,114,197,0,0,0, + 114,139,0,0,0,114,145,0,0,0,41,5,114,104,0,0, + 0,114,123,0,0,0,114,37,0,0,0,114,56,0,0,0, + 114,206,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,114,184,0,0,0,116,3,0,0,115,8,0, + 0,0,0,1,10,1,10,1,14,1,122,29,83,111,117,114, + 99,101,108,101,115,115,70,105,108,101,76,111,97,100,101,114, + 46,103,101,116,95,99,111,100,101,99,2,0,0,0,0,0, + 0,0,2,0,0,0,1,0,0,0,67,0,0,0,115,4, + 0,0,0,100,1,83,0,41,2,122,39,82,101,116,117,114, + 110,32,78,111,110,101,32,97,115,32,116,104,101,114,101,32, + 105,115,32,110,111,32,115,111,117,114,99,101,32,99,111,100, + 101,46,78,114,4,0,0,0,41,2,114,104,0,0,0,114, + 123,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,114,199,0,0,0,122,3,0,0,115,2,0,0, + 0,0,2,122,31,83,111,117,114,99,101,108,101,115,115,70, + 105,108,101,76,111,97,100,101,114,46,103,101,116,95,115,111, + 117,114,99,101,78,41,6,114,109,0,0,0,114,108,0,0, + 0,114,110,0,0,0,114,111,0,0,0,114,184,0,0,0, + 114,199,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,114,220,0,0,0,112,3, + 0,0,115,6,0,0,0,8,2,4,2,8,6,114,220,0, + 0,0,99,0,0,0,0,0,0,0,0,0,0,0,0,3, + 0,0,0,64,0,0,0,115,92,0,0,0,101,0,90,1, + 100,0,90,2,100,1,90,3,100,2,100,3,132,0,90,4, + 100,4,100,5,132,0,90,5,100,6,100,7,132,0,90,6, + 100,8,100,9,132,0,90,7,100,10,100,11,132,0,90,8, + 100,12,100,13,132,0,90,9,100,14,100,15,132,0,90,10, + 100,16,100,17,132,0,90,11,101,12,100,18,100,19,132,0, + 131,1,90,13,100,20,83,0,41,21,218,19,69,120,116,101, + 110,115,105,111,110,70,105,108,101,76,111,97,100,101,114,122, + 93,76,111,97,100,101,114,32,102,111,114,32,101,120,116,101, + 110,115,105,111,110,32,109,111,100,117,108,101,115,46,10,10, + 32,32,32,32,84,104,101,32,99,111,110,115,116,114,117,99, + 116,111,114,32,105,115,32,100,101,115,105,103,110,101,100,32, + 116,111,32,119,111,114,107,32,119,105,116,104,32,70,105,108, + 101,70,105,110,100,101,114,46,10,10,32,32,32,32,99,3, + 0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,67, + 0,0,0,115,16,0,0,0,124,1,124,0,95,0,124,2, + 124,0,95,1,100,0,83,0,41,1,78,41,2,114,102,0, + 0,0,114,37,0,0,0,41,3,114,104,0,0,0,114,102, + 0,0,0,114,37,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,182,0,0,0,139,3,0,0, + 115,4,0,0,0,0,1,6,1,122,28,69,120,116,101,110, + 115,105,111,110,70,105,108,101,76,111,97,100,101,114,46,95, + 95,105,110,105,116,95,95,99,2,0,0,0,0,0,0,0, + 2,0,0,0,2,0,0,0,67,0,0,0,115,24,0,0, + 0,124,0,106,0,124,1,106,0,107,2,111,22,124,0,106, + 1,124,1,106,1,107,2,83,0,41,1,78,41,2,114,208, + 0,0,0,114,115,0,0,0,41,2,114,104,0,0,0,114, + 209,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,114,210,0,0,0,143,3,0,0,115,4,0,0, + 0,0,1,12,1,122,26,69,120,116,101,110,115,105,111,110, + 70,105,108,101,76,111,97,100,101,114,46,95,95,101,113,95, + 95,99,1,0,0,0,0,0,0,0,1,0,0,0,3,0, + 0,0,67,0,0,0,115,20,0,0,0,116,0,124,0,106, + 1,131,1,116,0,124,0,106,2,131,1,65,0,83,0,41, + 1,78,41,3,114,211,0,0,0,114,102,0,0,0,114,37, + 0,0,0,41,1,114,104,0,0,0,114,4,0,0,0,114, + 4,0,0,0,114,6,0,0,0,114,212,0,0,0,147,3, + 0,0,115,2,0,0,0,0,1,122,28,69,120,116,101,110, + 115,105,111,110,70,105,108,101,76,111,97,100,101,114,46,95, + 95,104,97,115,104,95,95,99,2,0,0,0,0,0,0,0, + 3,0,0,0,4,0,0,0,67,0,0,0,115,36,0,0, + 0,116,0,106,1,116,2,106,3,124,1,131,2,125,2,116, + 0,106,4,100,1,124,1,106,5,124,0,106,6,131,3,1, + 0,124,2,83,0,41,2,122,38,67,114,101,97,116,101,32, + 97,110,32,117,110,105,116,105,97,108,105,122,101,100,32,101, + 120,116,101,110,115,105,111,110,32,109,111,100,117,108,101,122, + 38,101,120,116,101,110,115,105,111,110,32,109,111,100,117,108, + 101,32,123,33,114,125,32,108,111,97,100,101,100,32,102,114, + 111,109,32,123,33,114,125,41,7,114,118,0,0,0,114,185, + 0,0,0,114,143,0,0,0,90,14,99,114,101,97,116,101, + 95,100,121,110,97,109,105,99,114,133,0,0,0,114,102,0, + 0,0,114,37,0,0,0,41,3,114,104,0,0,0,114,162, + 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,183,0,0,0,150,3,0,0, + 115,10,0,0,0,0,2,4,1,10,1,6,1,12,1,122, + 33,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, + 97,100,101,114,46,99,114,101,97,116,101,95,109,111,100,117, + 108,101,99,2,0,0,0,0,0,0,0,2,0,0,0,4, + 0,0,0,67,0,0,0,115,36,0,0,0,116,0,106,1, + 116,2,106,3,124,1,131,2,1,0,116,0,106,4,100,1, + 124,0,106,5,124,0,106,6,131,3,1,0,100,2,83,0, + 41,3,122,30,73,110,105,116,105,97,108,105,122,101,32,97, + 110,32,101,120,116,101,110,115,105,111,110,32,109,111,100,117, + 108,101,122,40,101,120,116,101,110,115,105,111,110,32,109,111, + 100,117,108,101,32,123,33,114,125,32,101,120,101,99,117,116, + 101,100,32,102,114,111,109,32,123,33,114,125,78,41,7,114, + 118,0,0,0,114,185,0,0,0,114,143,0,0,0,90,12, + 101,120,101,99,95,100,121,110,97,109,105,99,114,133,0,0, + 0,114,102,0,0,0,114,37,0,0,0,41,2,114,104,0, + 0,0,114,187,0,0,0,114,4,0,0,0,114,4,0,0, + 0,114,6,0,0,0,114,188,0,0,0,158,3,0,0,115, + 6,0,0,0,0,2,14,1,6,1,122,31,69,120,116,101, + 110,115,105,111,110,70,105,108,101,76,111,97,100,101,114,46, + 101,120,101,99,95,109,111,100,117,108,101,99,2,0,0,0, + 0,0,0,0,2,0,0,0,4,0,0,0,3,0,0,0, + 115,36,0,0,0,116,0,124,0,106,1,131,1,100,1,25, + 0,137,0,116,2,135,0,102,1,100,2,100,3,132,8,116, + 3,68,0,131,1,131,1,83,0,41,4,122,49,82,101,116, + 117,114,110,32,84,114,117,101,32,105,102,32,116,104,101,32, + 101,120,116,101,110,115,105,111,110,32,109,111,100,117,108,101, + 32,105,115,32,97,32,112,97,99,107,97,103,101,46,114,31, + 0,0,0,99,1,0,0,0,0,0,0,0,2,0,0,0, + 4,0,0,0,51,0,0,0,115,26,0,0,0,124,0,93, + 18,125,1,136,0,100,0,124,1,23,0,107,2,86,0,1, + 0,113,2,100,1,83,0,41,2,114,182,0,0,0,78,114, + 4,0,0,0,41,2,114,24,0,0,0,218,6,115,117,102, + 102,105,120,41,1,218,9,102,105,108,101,95,110,97,109,101, + 114,4,0,0,0,114,6,0,0,0,250,9,60,103,101,110, + 101,120,112,114,62,167,3,0,0,115,2,0,0,0,4,1, + 122,49,69,120,116,101,110,115,105,111,110,70,105,108,101,76, + 111,97,100,101,114,46,105,115,95,112,97,99,107,97,103,101, + 46,60,108,111,99,97,108,115,62,46,60,103,101,110,101,120, + 112,114,62,41,4,114,40,0,0,0,114,37,0,0,0,218, + 3,97,110,121,218,18,69,88,84,69,78,83,73,79,78,95, + 83,85,70,70,73,88,69,83,41,2,114,104,0,0,0,114, + 123,0,0,0,114,4,0,0,0,41,1,114,223,0,0,0, + 114,6,0,0,0,114,157,0,0,0,164,3,0,0,115,6, + 0,0,0,0,2,14,1,12,1,122,30,69,120,116,101,110, + 115,105,111,110,70,105,108,101,76,111,97,100,101,114,46,105, + 115,95,112,97,99,107,97,103,101,99,2,0,0,0,0,0, + 0,0,2,0,0,0,1,0,0,0,67,0,0,0,115,4, + 0,0,0,100,1,83,0,41,2,122,63,82,101,116,117,114, + 110,32,78,111,110,101,32,97,115,32,97,110,32,101,120,116, + 101,110,115,105,111,110,32,109,111,100,117,108,101,32,99,97, + 110,110,111,116,32,99,114,101,97,116,101,32,97,32,99,111, + 100,101,32,111,98,106,101,99,116,46,78,114,4,0,0,0, 41,2,114,104,0,0,0,114,123,0,0,0,114,4,0,0, - 0,114,4,0,0,0,114,6,0,0,0,114,155,0,0,0, - 56,3,0,0,115,2,0,0,0,0,3,122,23,70,105,108, - 101,76,111,97,100,101,114,46,103,101,116,95,102,105,108,101, - 110,97,109,101,99,2,0,0,0,0,0,0,0,3,0,0, - 0,9,0,0,0,67,0,0,0,115,32,0,0,0,116,0, - 106,1,124,1,100,1,131,2,143,10,125,2,124,2,106,2, - 131,0,83,0,81,0,82,0,88,0,100,2,83,0,41,3, - 122,39,82,101,116,117,114,110,32,116,104,101,32,100,97,116, - 97,32,102,114,111,109,32,112,97,116,104,32,97,115,32,114, - 97,119,32,98,121,116,101,115,46,218,1,114,78,41,3,114, - 52,0,0,0,114,53,0,0,0,90,4,114,101,97,100,41, - 3,114,104,0,0,0,114,37,0,0,0,114,57,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 197,0,0,0,61,3,0,0,115,4,0,0,0,0,2,14, - 1,122,19,70,105,108,101,76,111,97,100,101,114,46,103,101, - 116,95,100,97,116,97,78,41,12,114,109,0,0,0,114,108, - 0,0,0,114,110,0,0,0,114,111,0,0,0,114,182,0, - 0,0,114,210,0,0,0,114,212,0,0,0,114,120,0,0, - 0,114,190,0,0,0,114,155,0,0,0,114,197,0,0,0, - 90,13,95,95,99,108,97,115,115,99,101,108,108,95,95,114, - 4,0,0,0,114,4,0,0,0,41,1,114,208,0,0,0, - 114,6,0,0,0,114,207,0,0,0,26,3,0,0,115,14, - 0,0,0,8,3,4,2,8,6,8,4,8,3,16,12,12, - 5,114,207,0,0,0,99,0,0,0,0,0,0,0,0,0, - 0,0,0,3,0,0,0,64,0,0,0,115,46,0,0,0, - 101,0,90,1,100,0,90,2,100,1,90,3,100,2,100,3, - 132,0,90,4,100,4,100,5,132,0,90,5,100,6,100,7, - 156,1,100,8,100,9,132,2,90,6,100,10,83,0,41,11, - 218,16,83,111,117,114,99,101,70,105,108,101,76,111,97,100, - 101,114,122,62,67,111,110,99,114,101,116,101,32,105,109,112, - 108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,83, - 111,117,114,99,101,76,111,97,100,101,114,32,117,115,105,110, - 103,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101, - 109,46,99,2,0,0,0,0,0,0,0,3,0,0,0,3, - 0,0,0,67,0,0,0,115,22,0,0,0,116,0,124,1, - 131,1,125,2,124,2,106,1,124,2,106,2,100,1,156,2, - 83,0,41,2,122,33,82,101,116,117,114,110,32,116,104,101, - 32,109,101,116,97,100,97,116,97,32,102,111,114,32,116,104, - 101,32,112,97,116,104,46,41,2,114,130,0,0,0,114,131, - 0,0,0,41,3,114,41,0,0,0,218,8,115,116,95,109, - 116,105,109,101,90,7,115,116,95,115,105,122,101,41,3,114, - 104,0,0,0,114,37,0,0,0,114,205,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,194,0, - 0,0,71,3,0,0,115,4,0,0,0,0,2,8,1,122, - 27,83,111,117,114,99,101,70,105,108,101,76,111,97,100,101, - 114,46,112,97,116,104,95,115,116,97,116,115,99,4,0,0, - 0,0,0,0,0,5,0,0,0,5,0,0,0,67,0,0, - 0,115,24,0,0,0,116,0,124,1,131,1,125,4,124,0, - 106,1,124,2,124,3,124,4,100,1,141,3,83,0,41,2, - 78,41,1,218,5,95,109,111,100,101,41,2,114,101,0,0, - 0,114,195,0,0,0,41,5,114,104,0,0,0,114,94,0, - 0,0,114,93,0,0,0,114,56,0,0,0,114,44,0,0, - 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,196,0,0,0,76,3,0,0,115,4,0,0,0,0,2, - 8,1,122,32,83,111,117,114,99,101,70,105,108,101,76,111, - 97,100,101,114,46,95,99,97,99,104,101,95,98,121,116,101, - 99,111,100,101,105,182,1,0,0,41,1,114,217,0,0,0, - 99,3,0,0,0,1,0,0,0,9,0,0,0,17,0,0, - 0,67,0,0,0,115,250,0,0,0,116,0,124,1,131,1, - 92,2,125,4,125,5,103,0,125,6,120,40,124,4,114,56, - 116,1,124,4,131,1,12,0,114,56,116,0,124,4,131,1, - 92,2,125,4,125,7,124,6,106,2,124,7,131,1,1,0, - 113,18,87,0,120,108,116,3,124,6,131,1,68,0,93,96, - 125,7,116,4,124,4,124,7,131,2,125,4,121,14,116,5, - 106,6,124,4,131,1,1,0,87,0,113,68,4,0,116,7, - 107,10,114,118,1,0,1,0,1,0,119,68,89,0,113,68, - 4,0,116,8,107,10,114,162,1,0,125,8,1,0,122,18, - 116,9,106,10,100,1,124,4,124,8,131,3,1,0,100,2, - 83,0,100,2,125,8,126,8,88,0,113,68,88,0,113,68, - 87,0,121,28,116,11,124,1,124,2,124,3,131,3,1,0, - 116,9,106,10,100,3,124,1,131,2,1,0,87,0,110,48, - 4,0,116,8,107,10,114,244,1,0,125,8,1,0,122,20, - 116,9,106,10,100,1,124,1,124,8,131,3,1,0,87,0, - 89,0,100,2,100,2,125,8,126,8,88,0,110,2,88,0, - 100,2,83,0,41,4,122,27,87,114,105,116,101,32,98,121, - 116,101,115,32,100,97,116,97,32,116,111,32,97,32,102,105, - 108,101,46,122,27,99,111,117,108,100,32,110,111,116,32,99, - 114,101,97,116,101,32,123,33,114,125,58,32,123,33,114,125, - 78,122,12,99,114,101,97,116,101,100,32,123,33,114,125,41, - 12,114,40,0,0,0,114,48,0,0,0,114,161,0,0,0, - 114,35,0,0,0,114,30,0,0,0,114,3,0,0,0,90, - 5,109,107,100,105,114,218,15,70,105,108,101,69,120,105,115, - 116,115,69,114,114,111,114,114,42,0,0,0,114,118,0,0, - 0,114,133,0,0,0,114,58,0,0,0,41,9,114,104,0, - 0,0,114,37,0,0,0,114,56,0,0,0,114,217,0,0, - 0,218,6,112,97,114,101,110,116,114,98,0,0,0,114,29, - 0,0,0,114,25,0,0,0,114,198,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,114,195,0,0, - 0,81,3,0,0,115,42,0,0,0,0,2,12,1,4,2, - 16,1,12,1,14,2,14,1,10,1,2,1,14,1,14,2, - 6,1,16,3,6,1,8,1,20,1,2,1,12,1,16,1, - 16,2,8,1,122,25,83,111,117,114,99,101,70,105,108,101, - 76,111,97,100,101,114,46,115,101,116,95,100,97,116,97,78, - 41,7,114,109,0,0,0,114,108,0,0,0,114,110,0,0, - 0,114,111,0,0,0,114,194,0,0,0,114,196,0,0,0, - 114,195,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,215,0,0,0,67,3, - 0,0,115,8,0,0,0,8,2,4,2,8,5,8,5,114, - 215,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, - 0,2,0,0,0,64,0,0,0,115,32,0,0,0,101,0, - 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0, - 90,4,100,4,100,5,132,0,90,5,100,6,83,0,41,7, - 218,20,83,111,117,114,99,101,108,101,115,115,70,105,108,101, - 76,111,97,100,101,114,122,45,76,111,97,100,101,114,32,119, - 104,105,99,104,32,104,97,110,100,108,101,115,32,115,111,117, - 114,99,101,108,101,115,115,32,102,105,108,101,32,105,109,112, - 111,114,116,115,46,99,2,0,0,0,0,0,0,0,5,0, - 0,0,5,0,0,0,67,0,0,0,115,48,0,0,0,124, - 0,106,0,124,1,131,1,125,2,124,0,106,1,124,2,131, - 1,125,3,116,2,124,3,124,1,124,2,100,1,141,3,125, - 4,116,3,124,4,124,1,124,2,100,2,141,3,83,0,41, - 3,78,41,2,114,102,0,0,0,114,37,0,0,0,41,2, - 114,102,0,0,0,114,93,0,0,0,41,4,114,155,0,0, - 0,114,197,0,0,0,114,139,0,0,0,114,145,0,0,0, - 41,5,114,104,0,0,0,114,123,0,0,0,114,37,0,0, - 0,114,56,0,0,0,114,206,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,116, - 3,0,0,115,8,0,0,0,0,1,10,1,10,1,14,1, - 122,29,83,111,117,114,99,101,108,101,115,115,70,105,108,101, - 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, - 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 39,82,101,116,117,114,110,32,78,111,110,101,32,97,115,32, - 116,104,101,114,101,32,105,115,32,110,111,32,115,111,117,114, - 99,101,32,99,111,100,101,46,78,114,4,0,0,0,41,2, - 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,199,0,0,0,122,3, - 0,0,115,2,0,0,0,0,2,122,31,83,111,117,114,99, - 101,108,101,115,115,70,105,108,101,76,111,97,100,101,114,46, - 103,101,116,95,115,111,117,114,99,101,78,41,6,114,109,0, - 0,0,114,108,0,0,0,114,110,0,0,0,114,111,0,0, - 0,114,184,0,0,0,114,199,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 220,0,0,0,112,3,0,0,115,6,0,0,0,8,2,4, - 2,8,6,114,220,0,0,0,99,0,0,0,0,0,0,0, - 0,0,0,0,0,3,0,0,0,64,0,0,0,115,92,0, - 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, - 100,3,132,0,90,4,100,4,100,5,132,0,90,5,100,6, - 100,7,132,0,90,6,100,8,100,9,132,0,90,7,100,10, - 100,11,132,0,90,8,100,12,100,13,132,0,90,9,100,14, - 100,15,132,0,90,10,100,16,100,17,132,0,90,11,101,12, - 100,18,100,19,132,0,131,1,90,13,100,20,83,0,41,21, - 218,19,69,120,116,101,110,115,105,111,110,70,105,108,101,76, - 111,97,100,101,114,122,93,76,111,97,100,101,114,32,102,111, - 114,32,101,120,116,101,110,115,105,111,110,32,109,111,100,117, - 108,101,115,46,10,10,32,32,32,32,84,104,101,32,99,111, - 110,115,116,114,117,99,116,111,114,32,105,115,32,100,101,115, - 105,103,110,101,100,32,116,111,32,119,111,114,107,32,119,105, - 116,104,32,70,105,108,101,70,105,110,100,101,114,46,10,10, - 32,32,32,32,99,3,0,0,0,0,0,0,0,3,0,0, - 0,2,0,0,0,67,0,0,0,115,16,0,0,0,124,1, - 124,0,95,0,124,2,124,0,95,1,100,0,83,0,41,1, - 78,41,2,114,102,0,0,0,114,37,0,0,0,41,3,114, - 104,0,0,0,114,102,0,0,0,114,37,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,182,0, - 0,0,139,3,0,0,115,4,0,0,0,0,1,6,1,122, - 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, - 97,100,101,114,46,95,95,105,110,105,116,95,95,99,2,0, - 0,0,0,0,0,0,2,0,0,0,2,0,0,0,67,0, - 0,0,115,24,0,0,0,124,0,106,0,124,1,106,0,107, - 2,111,22,124,0,106,1,124,1,106,1,107,2,83,0,41, - 1,78,41,2,114,208,0,0,0,114,115,0,0,0,41,2, - 114,104,0,0,0,114,209,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,210,0,0,0,143,3, - 0,0,115,4,0,0,0,0,1,12,1,122,26,69,120,116, + 0,114,4,0,0,0,114,6,0,0,0,114,184,0,0,0, + 170,3,0,0,115,2,0,0,0,0,2,122,28,69,120,116, 101,110,115,105,111,110,70,105,108,101,76,111,97,100,101,114, - 46,95,95,101,113,95,95,99,1,0,0,0,0,0,0,0, - 1,0,0,0,3,0,0,0,67,0,0,0,115,20,0,0, - 0,116,0,124,0,106,1,131,1,116,0,124,0,106,2,131, - 1,65,0,83,0,41,1,78,41,3,114,211,0,0,0,114, - 102,0,0,0,114,37,0,0,0,41,1,114,104,0,0,0, - 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 212,0,0,0,147,3,0,0,115,2,0,0,0,0,1,122, - 28,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, - 97,100,101,114,46,95,95,104,97,115,104,95,95,99,2,0, - 0,0,0,0,0,0,3,0,0,0,4,0,0,0,67,0, - 0,0,115,36,0,0,0,116,0,106,1,116,2,106,3,124, - 1,131,2,125,2,116,0,106,4,100,1,124,1,106,5,124, - 0,106,6,131,3,1,0,124,2,83,0,41,2,122,38,67, - 114,101,97,116,101,32,97,110,32,117,110,105,116,105,97,108, - 105,122,101,100,32,101,120,116,101,110,115,105,111,110,32,109, - 111,100,117,108,101,122,38,101,120,116,101,110,115,105,111,110, - 32,109,111,100,117,108,101,32,123,33,114,125,32,108,111,97, - 100,101,100,32,102,114,111,109,32,123,33,114,125,41,7,114, - 118,0,0,0,114,185,0,0,0,114,143,0,0,0,90,14, - 99,114,101,97,116,101,95,100,121,110,97,109,105,99,114,133, - 0,0,0,114,102,0,0,0,114,37,0,0,0,41,3,114, - 104,0,0,0,114,162,0,0,0,114,187,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,183,0, - 0,0,150,3,0,0,115,10,0,0,0,0,2,4,1,10, - 1,6,1,12,1,122,33,69,120,116,101,110,115,105,111,110, - 70,105,108,101,76,111,97,100,101,114,46,99,114,101,97,116, - 101,95,109,111,100,117,108,101,99,2,0,0,0,0,0,0, - 0,2,0,0,0,4,0,0,0,67,0,0,0,115,36,0, - 0,0,116,0,106,1,116,2,106,3,124,1,131,2,1,0, - 116,0,106,4,100,1,124,0,106,5,124,0,106,6,131,3, - 1,0,100,2,83,0,41,3,122,30,73,110,105,116,105,97, - 108,105,122,101,32,97,110,32,101,120,116,101,110,115,105,111, - 110,32,109,111,100,117,108,101,122,40,101,120,116,101,110,115, - 105,111,110,32,109,111,100,117,108,101,32,123,33,114,125,32, - 101,120,101,99,117,116,101,100,32,102,114,111,109,32,123,33, - 114,125,78,41,7,114,118,0,0,0,114,185,0,0,0,114, - 143,0,0,0,90,12,101,120,101,99,95,100,121,110,97,109, - 105,99,114,133,0,0,0,114,102,0,0,0,114,37,0,0, - 0,41,2,114,104,0,0,0,114,187,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,114,188,0,0, - 0,158,3,0,0,115,6,0,0,0,0,2,14,1,6,1, - 122,31,69,120,116,101,110,115,105,111,110,70,105,108,101,76, - 111,97,100,101,114,46,101,120,101,99,95,109,111,100,117,108, - 101,99,2,0,0,0,0,0,0,0,2,0,0,0,4,0, - 0,0,3,0,0,0,115,36,0,0,0,116,0,124,0,106, - 1,131,1,100,1,25,0,137,0,116,2,135,0,102,1,100, - 2,100,3,132,8,116,3,68,0,131,1,131,1,83,0,41, - 4,122,49,82,101,116,117,114,110,32,84,114,117,101,32,105, - 102,32,116,104,101,32,101,120,116,101,110,115,105,111,110,32, - 109,111,100,117,108,101,32,105,115,32,97,32,112,97,99,107, - 97,103,101,46,114,31,0,0,0,99,1,0,0,0,0,0, - 0,0,2,0,0,0,4,0,0,0,51,0,0,0,115,26, - 0,0,0,124,0,93,18,125,1,136,0,100,0,124,1,23, - 0,107,2,86,0,1,0,113,2,100,1,83,0,41,2,114, - 182,0,0,0,78,114,4,0,0,0,41,2,114,24,0,0, - 0,218,6,115,117,102,102,105,120,41,1,218,9,102,105,108, - 101,95,110,97,109,101,114,4,0,0,0,114,6,0,0,0, - 250,9,60,103,101,110,101,120,112,114,62,167,3,0,0,115, - 2,0,0,0,4,1,122,49,69,120,116,101,110,115,105,111, - 110,70,105,108,101,76,111,97,100,101,114,46,105,115,95,112, - 97,99,107,97,103,101,46,60,108,111,99,97,108,115,62,46, - 60,103,101,110,101,120,112,114,62,41,4,114,40,0,0,0, - 114,37,0,0,0,218,3,97,110,121,218,18,69,88,84,69, - 78,83,73,79,78,95,83,85,70,70,73,88,69,83,41,2, - 114,104,0,0,0,114,123,0,0,0,114,4,0,0,0,41, - 1,114,223,0,0,0,114,6,0,0,0,114,157,0,0,0, - 164,3,0,0,115,6,0,0,0,0,2,14,1,12,1,122, - 30,69,120,116,101,110,115,105,111,110,70,105,108,101,76,111, - 97,100,101,114,46,105,115,95,112,97,99,107,97,103,101,99, - 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 63,82,101,116,117,114,110,32,78,111,110,101,32,97,115,32, - 97,110,32,101,120,116,101,110,115,105,111,110,32,109,111,100, - 117,108,101,32,99,97,110,110,111,116,32,99,114,101,97,116, - 101,32,97,32,99,111,100,101,32,111,98,106,101,99,116,46, + 46,103,101,116,95,99,111,100,101,99,2,0,0,0,0,0, + 0,0,2,0,0,0,1,0,0,0,67,0,0,0,115,4, + 0,0,0,100,1,83,0,41,2,122,53,82,101,116,117,114, + 110,32,78,111,110,101,32,97,115,32,101,120,116,101,110,115, + 105,111,110,32,109,111,100,117,108,101,115,32,104,97,118,101, + 32,110,111,32,115,111,117,114,99,101,32,99,111,100,101,46, 78,114,4,0,0,0,41,2,114,104,0,0,0,114,123,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,184,0,0,0,170,3,0,0,115,2,0,0,0,0, - 2,122,28,69,120,116,101,110,115,105,111,110,70,105,108,101, - 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, - 2,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 53,82,101,116,117,114,110,32,78,111,110,101,32,97,115,32, - 101,120,116,101,110,115,105,111,110,32,109,111,100,117,108,101, - 115,32,104,97,118,101,32,110,111,32,115,111,117,114,99,101, - 32,99,111,100,101,46,78,114,4,0,0,0,41,2,114,104, - 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,199,0,0,0,174,3,0,0, - 115,2,0,0,0,0,2,122,30,69,120,116,101,110,115,105, - 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, - 95,115,111,117,114,99,101,99,2,0,0,0,0,0,0,0, - 2,0,0,0,1,0,0,0,67,0,0,0,115,6,0,0, - 0,124,0,106,0,83,0,41,1,122,58,82,101,116,117,114, - 110,32,116,104,101,32,112,97,116,104,32,116,111,32,116,104, - 101,32,115,111,117,114,99,101,32,102,105,108,101,32,97,115, - 32,102,111,117,110,100,32,98,121,32,116,104,101,32,102,105, - 110,100,101,114,46,41,1,114,37,0,0,0,41,2,114,104, - 0,0,0,114,123,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,155,0,0,0,178,3,0,0, - 115,2,0,0,0,0,3,122,32,69,120,116,101,110,115,105, - 111,110,70,105,108,101,76,111,97,100,101,114,46,103,101,116, - 95,102,105,108,101,110,97,109,101,78,41,14,114,109,0,0, + 0,114,199,0,0,0,174,3,0,0,115,2,0,0,0,0, + 2,122,30,69,120,116,101,110,115,105,111,110,70,105,108,101, + 76,111,97,100,101,114,46,103,101,116,95,115,111,117,114,99, + 101,99,2,0,0,0,0,0,0,0,2,0,0,0,1,0, + 0,0,67,0,0,0,115,6,0,0,0,124,0,106,0,83, + 0,41,1,122,58,82,101,116,117,114,110,32,116,104,101,32, + 112,97,116,104,32,116,111,32,116,104,101,32,115,111,117,114, + 99,101,32,102,105,108,101,32,97,115,32,102,111,117,110,100, + 32,98,121,32,116,104,101,32,102,105,110,100,101,114,46,41, + 1,114,37,0,0,0,41,2,114,104,0,0,0,114,123,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,114,155,0,0,0,178,3,0,0,115,2,0,0,0,0, + 3,122,32,69,120,116,101,110,115,105,111,110,70,105,108,101, + 76,111,97,100,101,114,46,103,101,116,95,102,105,108,101,110, + 97,109,101,78,41,14,114,109,0,0,0,114,108,0,0,0, + 114,110,0,0,0,114,111,0,0,0,114,182,0,0,0,114, + 210,0,0,0,114,212,0,0,0,114,183,0,0,0,114,188, + 0,0,0,114,157,0,0,0,114,184,0,0,0,114,199,0, + 0,0,114,120,0,0,0,114,155,0,0,0,114,4,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 114,221,0,0,0,131,3,0,0,115,20,0,0,0,8,6, + 4,2,8,4,8,4,8,3,8,8,8,6,8,6,8,4, + 8,4,114,221,0,0,0,99,0,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0,64,0,0,0,115,96,0,0, + 0,101,0,90,1,100,0,90,2,100,1,90,3,100,2,100, + 3,132,0,90,4,100,4,100,5,132,0,90,5,100,6,100, + 7,132,0,90,6,100,8,100,9,132,0,90,7,100,10,100, + 11,132,0,90,8,100,12,100,13,132,0,90,9,100,14,100, + 15,132,0,90,10,100,16,100,17,132,0,90,11,100,18,100, + 19,132,0,90,12,100,20,100,21,132,0,90,13,100,22,83, + 0,41,23,218,14,95,78,97,109,101,115,112,97,99,101,80, + 97,116,104,97,38,1,0,0,82,101,112,114,101,115,101,110, + 116,115,32,97,32,110,97,109,101,115,112,97,99,101,32,112, + 97,99,107,97,103,101,39,115,32,112,97,116,104,46,32,32, + 73,116,32,117,115,101,115,32,116,104,101,32,109,111,100,117, + 108,101,32,110,97,109,101,10,32,32,32,32,116,111,32,102, + 105,110,100,32,105,116,115,32,112,97,114,101,110,116,32,109, + 111,100,117,108,101,44,32,97,110,100,32,102,114,111,109,32, + 116,104,101,114,101,32,105,116,32,108,111,111,107,115,32,117, + 112,32,116,104,101,32,112,97,114,101,110,116,39,115,10,32, + 32,32,32,95,95,112,97,116,104,95,95,46,32,32,87,104, + 101,110,32,116,104,105,115,32,99,104,97,110,103,101,115,44, + 32,116,104,101,32,109,111,100,117,108,101,39,115,32,111,119, + 110,32,112,97,116,104,32,105,115,32,114,101,99,111,109,112, + 117,116,101,100,44,10,32,32,32,32,117,115,105,110,103,32, + 112,97,116,104,95,102,105,110,100,101,114,46,32,32,70,111, + 114,32,116,111,112,45,108,101,118,101,108,32,109,111,100,117, + 108,101,115,44,32,116,104,101,32,112,97,114,101,110,116,32, + 109,111,100,117,108,101,39,115,32,112,97,116,104,10,32,32, + 32,32,105,115,32,115,121,115,46,112,97,116,104,46,99,4, + 0,0,0,0,0,0,0,4,0,0,0,2,0,0,0,67, + 0,0,0,115,36,0,0,0,124,1,124,0,95,0,124,2, + 124,0,95,1,116,2,124,0,106,3,131,0,131,1,124,0, + 95,4,124,3,124,0,95,5,100,0,83,0,41,1,78,41, + 6,218,5,95,110,97,109,101,218,5,95,112,97,116,104,114, + 97,0,0,0,218,16,95,103,101,116,95,112,97,114,101,110, + 116,95,112,97,116,104,218,17,95,108,97,115,116,95,112,97, + 114,101,110,116,95,112,97,116,104,218,12,95,112,97,116,104, + 95,102,105,110,100,101,114,41,4,114,104,0,0,0,114,102, + 0,0,0,114,37,0,0,0,218,11,112,97,116,104,95,102, + 105,110,100,101,114,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,114,182,0,0,0,191,3,0,0,115,8,0, + 0,0,0,1,6,1,6,1,14,1,122,23,95,78,97,109, + 101,115,112,97,99,101,80,97,116,104,46,95,95,105,110,105, + 116,95,95,99,1,0,0,0,0,0,0,0,4,0,0,0, + 3,0,0,0,67,0,0,0,115,38,0,0,0,124,0,106, + 0,106,1,100,1,131,1,92,3,125,1,125,2,125,3,124, + 2,100,2,107,2,114,30,100,6,83,0,124,1,100,5,102, + 2,83,0,41,7,122,62,82,101,116,117,114,110,115,32,97, + 32,116,117,112,108,101,32,111,102,32,40,112,97,114,101,110, + 116,45,109,111,100,117,108,101,45,110,97,109,101,44,32,112, + 97,114,101,110,116,45,112,97,116,104,45,97,116,116,114,45, + 110,97,109,101,41,114,61,0,0,0,114,32,0,0,0,114, + 8,0,0,0,114,37,0,0,0,90,8,95,95,112,97,116, + 104,95,95,41,2,114,8,0,0,0,114,37,0,0,0,41, + 2,114,228,0,0,0,114,34,0,0,0,41,4,114,104,0, + 0,0,114,219,0,0,0,218,3,100,111,116,90,2,109,101, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, + 23,95,102,105,110,100,95,112,97,114,101,110,116,95,112,97, + 116,104,95,110,97,109,101,115,197,3,0,0,115,8,0,0, + 0,0,2,18,1,8,2,4,3,122,38,95,78,97,109,101, + 115,112,97,99,101,80,97,116,104,46,95,102,105,110,100,95, + 112,97,114,101,110,116,95,112,97,116,104,95,110,97,109,101, + 115,99,1,0,0,0,0,0,0,0,3,0,0,0,3,0, + 0,0,67,0,0,0,115,28,0,0,0,124,0,106,0,131, + 0,92,2,125,1,125,2,116,1,116,2,106,3,124,1,25, + 0,124,2,131,2,83,0,41,1,78,41,4,114,235,0,0, + 0,114,114,0,0,0,114,8,0,0,0,218,7,109,111,100, + 117,108,101,115,41,3,114,104,0,0,0,90,18,112,97,114, + 101,110,116,95,109,111,100,117,108,101,95,110,97,109,101,90, + 14,112,97,116,104,95,97,116,116,114,95,110,97,109,101,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,114,230, + 0,0,0,207,3,0,0,115,4,0,0,0,0,1,12,1, + 122,31,95,78,97,109,101,115,112,97,99,101,80,97,116,104, + 46,95,103,101,116,95,112,97,114,101,110,116,95,112,97,116, + 104,99,1,0,0,0,0,0,0,0,3,0,0,0,3,0, + 0,0,67,0,0,0,115,80,0,0,0,116,0,124,0,106, + 1,131,0,131,1,125,1,124,1,124,0,106,2,107,3,114, + 74,124,0,106,3,124,0,106,4,124,1,131,2,125,2,124, + 2,100,0,107,9,114,68,124,2,106,5,100,0,107,8,114, + 68,124,2,106,6,114,68,124,2,106,6,124,0,95,7,124, + 1,124,0,95,2,124,0,106,7,83,0,41,1,78,41,8, + 114,97,0,0,0,114,230,0,0,0,114,231,0,0,0,114, + 232,0,0,0,114,228,0,0,0,114,124,0,0,0,114,154, + 0,0,0,114,229,0,0,0,41,3,114,104,0,0,0,90, + 11,112,97,114,101,110,116,95,112,97,116,104,114,162,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,12,95,114,101,99,97,108,99,117,108,97,116,101,211,3, + 0,0,115,16,0,0,0,0,2,12,1,10,1,14,3,18, + 1,6,1,8,1,6,1,122,27,95,78,97,109,101,115,112, + 97,99,101,80,97,116,104,46,95,114,101,99,97,108,99,117, + 108,97,116,101,99,1,0,0,0,0,0,0,0,1,0,0, + 0,2,0,0,0,67,0,0,0,115,12,0,0,0,116,0, + 124,0,106,1,131,0,131,1,83,0,41,1,78,41,2,218, + 4,105,116,101,114,114,237,0,0,0,41,1,114,104,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 218,8,95,95,105,116,101,114,95,95,224,3,0,0,115,2, + 0,0,0,0,1,122,23,95,78,97,109,101,115,112,97,99, + 101,80,97,116,104,46,95,95,105,116,101,114,95,95,99,3, + 0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,67, + 0,0,0,115,14,0,0,0,124,2,124,0,106,0,124,1, + 60,0,100,0,83,0,41,1,78,41,1,114,229,0,0,0, + 41,3,114,104,0,0,0,218,5,105,110,100,101,120,114,37, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,218,11,95,95,115,101,116,105,116,101,109,95,95,227, + 3,0,0,115,2,0,0,0,0,1,122,26,95,78,97,109, + 101,115,112,97,99,101,80,97,116,104,46,95,95,115,101,116, + 105,116,101,109,95,95,99,1,0,0,0,0,0,0,0,1, + 0,0,0,2,0,0,0,67,0,0,0,115,12,0,0,0, + 116,0,124,0,106,1,131,0,131,1,83,0,41,1,78,41, + 2,114,33,0,0,0,114,237,0,0,0,41,1,114,104,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,218,7,95,95,108,101,110,95,95,230,3,0,0,115,2, + 0,0,0,0,1,122,22,95,78,97,109,101,115,112,97,99, + 101,80,97,116,104,46,95,95,108,101,110,95,95,99,1,0, + 0,0,0,0,0,0,1,0,0,0,2,0,0,0,67,0, + 0,0,115,12,0,0,0,100,1,106,0,124,0,106,1,131, + 1,83,0,41,2,78,122,20,95,78,97,109,101,115,112,97, + 99,101,80,97,116,104,40,123,33,114,125,41,41,2,114,50, + 0,0,0,114,229,0,0,0,41,1,114,104,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,8, + 95,95,114,101,112,114,95,95,233,3,0,0,115,2,0,0, + 0,0,1,122,23,95,78,97,109,101,115,112,97,99,101,80, + 97,116,104,46,95,95,114,101,112,114,95,95,99,2,0,0, + 0,0,0,0,0,2,0,0,0,2,0,0,0,67,0,0, + 0,115,12,0,0,0,124,1,124,0,106,0,131,0,107,6, + 83,0,41,1,78,41,1,114,237,0,0,0,41,2,114,104, + 0,0,0,218,4,105,116,101,109,114,4,0,0,0,114,4, + 0,0,0,114,6,0,0,0,218,12,95,95,99,111,110,116, + 97,105,110,115,95,95,236,3,0,0,115,2,0,0,0,0, + 1,122,27,95,78,97,109,101,115,112,97,99,101,80,97,116, + 104,46,95,95,99,111,110,116,97,105,110,115,95,95,99,2, + 0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,67, + 0,0,0,115,16,0,0,0,124,0,106,0,106,1,124,1, + 131,1,1,0,100,0,83,0,41,1,78,41,2,114,229,0, + 0,0,114,161,0,0,0,41,2,114,104,0,0,0,114,244, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,161,0,0,0,239,3,0,0,115,2,0,0,0, + 0,1,122,21,95,78,97,109,101,115,112,97,99,101,80,97, + 116,104,46,97,112,112,101,110,100,78,41,14,114,109,0,0, 0,114,108,0,0,0,114,110,0,0,0,114,111,0,0,0, - 114,182,0,0,0,114,210,0,0,0,114,212,0,0,0,114, - 183,0,0,0,114,188,0,0,0,114,157,0,0,0,114,184, - 0,0,0,114,199,0,0,0,114,120,0,0,0,114,155,0, + 114,182,0,0,0,114,235,0,0,0,114,230,0,0,0,114, + 237,0,0,0,114,239,0,0,0,114,241,0,0,0,114,242, + 0,0,0,114,243,0,0,0,114,245,0,0,0,114,161,0, 0,0,114,4,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,114,221,0,0,0,131,3,0,0,115, - 20,0,0,0,8,6,4,2,8,4,8,4,8,3,8,8, - 8,6,8,6,8,4,8,4,114,221,0,0,0,99,0,0, - 0,0,0,0,0,0,0,0,0,0,2,0,0,0,64,0, - 0,0,115,96,0,0,0,101,0,90,1,100,0,90,2,100, - 1,90,3,100,2,100,3,132,0,90,4,100,4,100,5,132, - 0,90,5,100,6,100,7,132,0,90,6,100,8,100,9,132, - 0,90,7,100,10,100,11,132,0,90,8,100,12,100,13,132, - 0,90,9,100,14,100,15,132,0,90,10,100,16,100,17,132, - 0,90,11,100,18,100,19,132,0,90,12,100,20,100,21,132, - 0,90,13,100,22,83,0,41,23,218,14,95,78,97,109,101, - 115,112,97,99,101,80,97,116,104,97,38,1,0,0,82,101, - 112,114,101,115,101,110,116,115,32,97,32,110,97,109,101,115, - 112,97,99,101,32,112,97,99,107,97,103,101,39,115,32,112, - 97,116,104,46,32,32,73,116,32,117,115,101,115,32,116,104, - 101,32,109,111,100,117,108,101,32,110,97,109,101,10,32,32, - 32,32,116,111,32,102,105,110,100,32,105,116,115,32,112,97, - 114,101,110,116,32,109,111,100,117,108,101,44,32,97,110,100, - 32,102,114,111,109,32,116,104,101,114,101,32,105,116,32,108, - 111,111,107,115,32,117,112,32,116,104,101,32,112,97,114,101, - 110,116,39,115,10,32,32,32,32,95,95,112,97,116,104,95, - 95,46,32,32,87,104,101,110,32,116,104,105,115,32,99,104, - 97,110,103,101,115,44,32,116,104,101,32,109,111,100,117,108, - 101,39,115,32,111,119,110,32,112,97,116,104,32,105,115,32, - 114,101,99,111,109,112,117,116,101,100,44,10,32,32,32,32, - 117,115,105,110,103,32,112,97,116,104,95,102,105,110,100,101, - 114,46,32,32,70,111,114,32,116,111,112,45,108,101,118,101, - 108,32,109,111,100,117,108,101,115,44,32,116,104,101,32,112, - 97,114,101,110,116,32,109,111,100,117,108,101,39,115,32,112, - 97,116,104,10,32,32,32,32,105,115,32,115,121,115,46,112, - 97,116,104,46,99,4,0,0,0,0,0,0,0,4,0,0, - 0,2,0,0,0,67,0,0,0,115,36,0,0,0,124,1, - 124,0,95,0,124,2,124,0,95,1,116,2,124,0,106,3, - 131,0,131,1,124,0,95,4,124,3,124,0,95,5,100,0, - 83,0,41,1,78,41,6,218,5,95,110,97,109,101,218,5, - 95,112,97,116,104,114,97,0,0,0,218,16,95,103,101,116, - 95,112,97,114,101,110,116,95,112,97,116,104,218,17,95,108, - 97,115,116,95,112,97,114,101,110,116,95,112,97,116,104,218, - 12,95,112,97,116,104,95,102,105,110,100,101,114,41,4,114, - 104,0,0,0,114,102,0,0,0,114,37,0,0,0,218,11, - 112,97,116,104,95,102,105,110,100,101,114,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,182,0,0,0,191, - 3,0,0,115,8,0,0,0,0,1,6,1,6,1,14,1, - 122,23,95,78,97,109,101,115,112,97,99,101,80,97,116,104, - 46,95,95,105,110,105,116,95,95,99,1,0,0,0,0,0, - 0,0,4,0,0,0,3,0,0,0,67,0,0,0,115,38, - 0,0,0,124,0,106,0,106,1,100,1,131,1,92,3,125, - 1,125,2,125,3,124,2,100,2,107,2,114,30,100,6,83, - 0,124,1,100,5,102,2,83,0,41,7,122,62,82,101,116, - 117,114,110,115,32,97,32,116,117,112,108,101,32,111,102,32, - 40,112,97,114,101,110,116,45,109,111,100,117,108,101,45,110, - 97,109,101,44,32,112,97,114,101,110,116,45,112,97,116,104, - 45,97,116,116,114,45,110,97,109,101,41,114,61,0,0,0, - 114,32,0,0,0,114,8,0,0,0,114,37,0,0,0,90, - 8,95,95,112,97,116,104,95,95,41,2,114,8,0,0,0, - 114,37,0,0,0,41,2,114,228,0,0,0,114,34,0,0, - 0,41,4,114,104,0,0,0,114,219,0,0,0,218,3,100, - 111,116,90,2,109,101,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,218,23,95,102,105,110,100,95,112,97,114, - 101,110,116,95,112,97,116,104,95,110,97,109,101,115,197,3, - 0,0,115,8,0,0,0,0,2,18,1,8,2,4,3,122, - 38,95,78,97,109,101,115,112,97,99,101,80,97,116,104,46, - 95,102,105,110,100,95,112,97,114,101,110,116,95,112,97,116, - 104,95,110,97,109,101,115,99,1,0,0,0,0,0,0,0, - 3,0,0,0,3,0,0,0,67,0,0,0,115,28,0,0, - 0,124,0,106,0,131,0,92,2,125,1,125,2,116,1,116, - 2,106,3,124,1,25,0,124,2,131,2,83,0,41,1,78, - 41,4,114,235,0,0,0,114,114,0,0,0,114,8,0,0, - 0,218,7,109,111,100,117,108,101,115,41,3,114,104,0,0, - 0,90,18,112,97,114,101,110,116,95,109,111,100,117,108,101, - 95,110,97,109,101,90,14,112,97,116,104,95,97,116,116,114, - 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,230,0,0,0,207,3,0,0,115,4,0, - 0,0,0,1,12,1,122,31,95,78,97,109,101,115,112,97, - 99,101,80,97,116,104,46,95,103,101,116,95,112,97,114,101, - 110,116,95,112,97,116,104,99,1,0,0,0,0,0,0,0, - 3,0,0,0,3,0,0,0,67,0,0,0,115,80,0,0, - 0,116,0,124,0,106,1,131,0,131,1,125,1,124,1,124, - 0,106,2,107,3,114,74,124,0,106,3,124,0,106,4,124, - 1,131,2,125,2,124,2,100,0,107,9,114,68,124,2,106, - 5,100,0,107,8,114,68,124,2,106,6,114,68,124,2,106, - 6,124,0,95,7,124,1,124,0,95,2,124,0,106,7,83, - 0,41,1,78,41,8,114,97,0,0,0,114,230,0,0,0, - 114,231,0,0,0,114,232,0,0,0,114,228,0,0,0,114, - 124,0,0,0,114,154,0,0,0,114,229,0,0,0,41,3, - 114,104,0,0,0,90,11,112,97,114,101,110,116,95,112,97, - 116,104,114,162,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,12,95,114,101,99,97,108,99,117, - 108,97,116,101,211,3,0,0,115,16,0,0,0,0,2,12, - 1,10,1,14,3,18,1,6,1,8,1,6,1,122,27,95, - 78,97,109,101,115,112,97,99,101,80,97,116,104,46,95,114, - 101,99,97,108,99,117,108,97,116,101,99,1,0,0,0,0, - 0,0,0,1,0,0,0,2,0,0,0,67,0,0,0,115, - 12,0,0,0,116,0,124,0,106,1,131,0,131,1,83,0, - 41,1,78,41,2,218,4,105,116,101,114,114,237,0,0,0, - 41,1,114,104,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,8,95,95,105,116,101,114,95,95, - 224,3,0,0,115,2,0,0,0,0,1,122,23,95,78,97, - 109,101,115,112,97,99,101,80,97,116,104,46,95,95,105,116, - 101,114,95,95,99,3,0,0,0,0,0,0,0,3,0,0, - 0,3,0,0,0,67,0,0,0,115,14,0,0,0,124,2, - 124,0,106,0,124,1,60,0,100,0,83,0,41,1,78,41, - 1,114,229,0,0,0,41,3,114,104,0,0,0,218,5,105, - 110,100,101,120,114,37,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,218,11,95,95,115,101,116,105, - 116,101,109,95,95,227,3,0,0,115,2,0,0,0,0,1, - 122,26,95,78,97,109,101,115,112,97,99,101,80,97,116,104, - 46,95,95,115,101,116,105,116,101,109,95,95,99,1,0,0, - 0,0,0,0,0,1,0,0,0,2,0,0,0,67,0,0, - 0,115,12,0,0,0,116,0,124,0,106,1,131,0,131,1, - 83,0,41,1,78,41,2,114,33,0,0,0,114,237,0,0, - 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,218,7,95,95,108,101,110,95,95, - 230,3,0,0,115,2,0,0,0,0,1,122,22,95,78,97, - 109,101,115,112,97,99,101,80,97,116,104,46,95,95,108,101, - 110,95,95,99,1,0,0,0,0,0,0,0,1,0,0,0, - 2,0,0,0,67,0,0,0,115,12,0,0,0,100,1,106, - 0,124,0,106,1,131,1,83,0,41,2,78,122,20,95,78, - 97,109,101,115,112,97,99,101,80,97,116,104,40,123,33,114, - 125,41,41,2,114,50,0,0,0,114,229,0,0,0,41,1, - 114,104,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,218,8,95,95,114,101,112,114,95,95,233,3, - 0,0,115,2,0,0,0,0,1,122,23,95,78,97,109,101, - 115,112,97,99,101,80,97,116,104,46,95,95,114,101,112,114, - 95,95,99,2,0,0,0,0,0,0,0,2,0,0,0,2, - 0,0,0,67,0,0,0,115,12,0,0,0,124,1,124,0, - 106,0,131,0,107,6,83,0,41,1,78,41,1,114,237,0, - 0,0,41,2,114,104,0,0,0,218,4,105,116,101,109,114, - 4,0,0,0,114,4,0,0,0,114,6,0,0,0,218,12, - 95,95,99,111,110,116,97,105,110,115,95,95,236,3,0,0, - 115,2,0,0,0,0,1,122,27,95,78,97,109,101,115,112, - 97,99,101,80,97,116,104,46,95,95,99,111,110,116,97,105, - 110,115,95,95,99,2,0,0,0,0,0,0,0,2,0,0, - 0,2,0,0,0,67,0,0,0,115,16,0,0,0,124,0, - 106,0,106,1,124,1,131,1,1,0,100,0,83,0,41,1, - 78,41,2,114,229,0,0,0,114,161,0,0,0,41,2,114, - 104,0,0,0,114,244,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,161,0,0,0,239,3,0, - 0,115,2,0,0,0,0,1,122,21,95,78,97,109,101,115, - 112,97,99,101,80,97,116,104,46,97,112,112,101,110,100,78, - 41,14,114,109,0,0,0,114,108,0,0,0,114,110,0,0, - 0,114,111,0,0,0,114,182,0,0,0,114,235,0,0,0, - 114,230,0,0,0,114,237,0,0,0,114,239,0,0,0,114, - 241,0,0,0,114,242,0,0,0,114,243,0,0,0,114,245, - 0,0,0,114,161,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,114,227,0,0, - 0,184,3,0,0,115,22,0,0,0,8,5,4,2,8,6, - 8,10,8,4,8,13,8,3,8,3,8,3,8,3,8,3, - 114,227,0,0,0,99,0,0,0,0,0,0,0,0,0,0, - 0,0,3,0,0,0,64,0,0,0,115,80,0,0,0,101, - 0,90,1,100,0,90,2,100,1,100,2,132,0,90,3,101, - 4,100,3,100,4,132,0,131,1,90,5,100,5,100,6,132, - 0,90,6,100,7,100,8,132,0,90,7,100,9,100,10,132, - 0,90,8,100,11,100,12,132,0,90,9,100,13,100,14,132, - 0,90,10,100,15,100,16,132,0,90,11,100,17,83,0,41, - 18,218,16,95,78,97,109,101,115,112,97,99,101,76,111,97, - 100,101,114,99,4,0,0,0,0,0,0,0,4,0,0,0, - 4,0,0,0,67,0,0,0,115,18,0,0,0,116,0,124, - 1,124,2,124,3,131,3,124,0,95,1,100,0,83,0,41, - 1,78,41,2,114,227,0,0,0,114,229,0,0,0,41,4, - 114,104,0,0,0,114,102,0,0,0,114,37,0,0,0,114, - 233,0,0,0,114,4,0,0,0,114,4,0,0,0,114,6, - 0,0,0,114,182,0,0,0,245,3,0,0,115,2,0,0, - 0,0,1,122,25,95,78,97,109,101,115,112,97,99,101,76, - 111,97,100,101,114,46,95,95,105,110,105,116,95,95,99,2, - 0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,67, - 0,0,0,115,12,0,0,0,100,1,106,0,124,1,106,1, - 131,1,83,0,41,2,122,115,82,101,116,117,114,110,32,114, - 101,112,114,32,102,111,114,32,116,104,101,32,109,111,100,117, - 108,101,46,10,10,32,32,32,32,32,32,32,32,84,104,101, - 32,109,101,116,104,111,100,32,105,115,32,100,101,112,114,101, - 99,97,116,101,100,46,32,32,84,104,101,32,105,109,112,111, - 114,116,32,109,97,99,104,105,110,101,114,121,32,100,111,101, - 115,32,116,104,101,32,106,111,98,32,105,116,115,101,108,102, - 46,10,10,32,32,32,32,32,32,32,32,122,25,60,109,111, - 100,117,108,101,32,123,33,114,125,32,40,110,97,109,101,115, - 112,97,99,101,41,62,41,2,114,50,0,0,0,114,109,0, - 0,0,41,2,114,168,0,0,0,114,187,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,109, - 111,100,117,108,101,95,114,101,112,114,248,3,0,0,115,2, - 0,0,0,0,7,122,28,95,78,97,109,101,115,112,97,99, - 101,76,111,97,100,101,114,46,109,111,100,117,108,101,95,114, - 101,112,114,99,2,0,0,0,0,0,0,0,2,0,0,0, - 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, - 0,41,2,78,84,114,4,0,0,0,41,2,114,104,0,0, - 0,114,123,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,114,157,0,0,0,1,4,0,0,115,2, - 0,0,0,0,1,122,27,95,78,97,109,101,115,112,97,99, - 101,76,111,97,100,101,114,46,105,115,95,112,97,99,107,97, - 103,101,99,2,0,0,0,0,0,0,0,2,0,0,0,1, - 0,0,0,67,0,0,0,115,4,0,0,0,100,1,83,0, - 41,2,78,114,32,0,0,0,114,4,0,0,0,41,2,114, - 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,199,0,0,0,4,4,0, - 0,115,2,0,0,0,0,1,122,27,95,78,97,109,101,115, - 112,97,99,101,76,111,97,100,101,114,46,103,101,116,95,115, - 111,117,114,99,101,99,2,0,0,0,0,0,0,0,2,0, - 0,0,6,0,0,0,67,0,0,0,115,16,0,0,0,116, - 0,100,1,100,2,100,3,100,4,100,5,141,4,83,0,41, - 6,78,114,32,0,0,0,122,8,60,115,116,114,105,110,103, - 62,114,186,0,0,0,84,41,1,114,201,0,0,0,41,1, - 114,202,0,0,0,41,2,114,104,0,0,0,114,123,0,0, + 0,114,6,0,0,0,114,227,0,0,0,184,3,0,0,115, + 22,0,0,0,8,5,4,2,8,6,8,10,8,4,8,13, + 8,3,8,3,8,3,8,3,8,3,114,227,0,0,0,99, + 0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0, + 64,0,0,0,115,80,0,0,0,101,0,90,1,100,0,90, + 2,100,1,100,2,132,0,90,3,101,4,100,3,100,4,132, + 0,131,1,90,5,100,5,100,6,132,0,90,6,100,7,100, + 8,132,0,90,7,100,9,100,10,132,0,90,8,100,11,100, + 12,132,0,90,9,100,13,100,14,132,0,90,10,100,15,100, + 16,132,0,90,11,100,17,83,0,41,18,218,16,95,78,97, + 109,101,115,112,97,99,101,76,111,97,100,101,114,99,4,0, + 0,0,0,0,0,0,4,0,0,0,4,0,0,0,67,0, + 0,0,115,18,0,0,0,116,0,124,1,124,2,124,3,131, + 3,124,0,95,1,100,0,83,0,41,1,78,41,2,114,227, + 0,0,0,114,229,0,0,0,41,4,114,104,0,0,0,114, + 102,0,0,0,114,37,0,0,0,114,233,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,182,0, + 0,0,245,3,0,0,115,2,0,0,0,0,1,122,25,95, + 78,97,109,101,115,112,97,99,101,76,111,97,100,101,114,46, + 95,95,105,110,105,116,95,95,99,2,0,0,0,0,0,0, + 0,2,0,0,0,2,0,0,0,67,0,0,0,115,12,0, + 0,0,100,1,106,0,124,1,106,1,131,1,83,0,41,2, + 122,115,82,101,116,117,114,110,32,114,101,112,114,32,102,111, + 114,32,116,104,101,32,109,111,100,117,108,101,46,10,10,32, + 32,32,32,32,32,32,32,84,104,101,32,109,101,116,104,111, + 100,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46, + 32,32,84,104,101,32,105,109,112,111,114,116,32,109,97,99, + 104,105,110,101,114,121,32,100,111,101,115,32,116,104,101,32, + 106,111,98,32,105,116,115,101,108,102,46,10,10,32,32,32, + 32,32,32,32,32,122,25,60,109,111,100,117,108,101,32,123, + 33,114,125,32,40,110,97,109,101,115,112,97,99,101,41,62, + 41,2,114,50,0,0,0,114,109,0,0,0,41,2,114,168, + 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,11,109,111,100,117,108,101,95, + 114,101,112,114,248,3,0,0,115,2,0,0,0,0,7,122, + 28,95,78,97,109,101,115,112,97,99,101,76,111,97,100,101, + 114,46,109,111,100,117,108,101,95,114,101,112,114,99,2,0, + 0,0,0,0,0,0,2,0,0,0,1,0,0,0,67,0, + 0,0,115,4,0,0,0,100,1,83,0,41,2,78,84,114, + 4,0,0,0,41,2,114,104,0,0,0,114,123,0,0,0, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, + 157,0,0,0,1,4,0,0,115,2,0,0,0,0,1,122, + 27,95,78,97,109,101,115,112,97,99,101,76,111,97,100,101, + 114,46,105,115,95,112,97,99,107,97,103,101,99,2,0,0, + 0,0,0,0,0,2,0,0,0,1,0,0,0,67,0,0, + 0,115,4,0,0,0,100,1,83,0,41,2,78,114,32,0, + 0,0,114,4,0,0,0,41,2,114,104,0,0,0,114,123, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,199,0,0,0,4,4,0,0,115,2,0,0,0, + 0,1,122,27,95,78,97,109,101,115,112,97,99,101,76,111, + 97,100,101,114,46,103,101,116,95,115,111,117,114,99,101,99, + 2,0,0,0,0,0,0,0,2,0,0,0,6,0,0,0, + 67,0,0,0,115,16,0,0,0,116,0,100,1,100,2,100, + 3,100,4,100,5,141,4,83,0,41,6,78,114,32,0,0, + 0,122,8,60,115,116,114,105,110,103,62,114,186,0,0,0, + 84,41,1,114,201,0,0,0,41,1,114,202,0,0,0,41, + 2,114,104,0,0,0,114,123,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,184,0,0,0,7, + 4,0,0,115,2,0,0,0,0,1,122,25,95,78,97,109, + 101,115,112,97,99,101,76,111,97,100,101,114,46,103,101,116, + 95,99,111,100,101,99,2,0,0,0,0,0,0,0,2,0, + 0,0,1,0,0,0,67,0,0,0,115,4,0,0,0,100, + 1,83,0,41,2,122,42,85,115,101,32,100,101,102,97,117, + 108,116,32,115,101,109,97,110,116,105,99,115,32,102,111,114, + 32,109,111,100,117,108,101,32,99,114,101,97,116,105,111,110, + 46,78,114,4,0,0,0,41,2,114,104,0,0,0,114,162, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,183,0,0,0,10,4,0,0,115,0,0,0,0, + 122,30,95,78,97,109,101,115,112,97,99,101,76,111,97,100, + 101,114,46,99,114,101,97,116,101,95,109,111,100,117,108,101, + 99,2,0,0,0,0,0,0,0,2,0,0,0,1,0,0, + 0,67,0,0,0,115,4,0,0,0,100,0,83,0,41,1, + 78,114,4,0,0,0,41,2,114,104,0,0,0,114,187,0, + 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,114,188,0,0,0,13,4,0,0,115,2,0,0,0,0, + 1,122,28,95,78,97,109,101,115,112,97,99,101,76,111,97, + 100,101,114,46,101,120,101,99,95,109,111,100,117,108,101,99, + 2,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0, + 67,0,0,0,115,26,0,0,0,116,0,106,1,100,1,124, + 0,106,2,131,2,1,0,116,0,106,3,124,0,124,1,131, + 2,83,0,41,2,122,98,76,111,97,100,32,97,32,110,97, + 109,101,115,112,97,99,101,32,109,111,100,117,108,101,46,10, + 10,32,32,32,32,32,32,32,32,84,104,105,115,32,109,101, + 116,104,111,100,32,105,115,32,100,101,112,114,101,99,97,116, + 101,100,46,32,32,85,115,101,32,101,120,101,99,95,109,111, + 100,117,108,101,40,41,32,105,110,115,116,101,97,100,46,10, + 10,32,32,32,32,32,32,32,32,122,38,110,97,109,101,115, + 112,97,99,101,32,109,111,100,117,108,101,32,108,111,97,100, + 101,100,32,119,105,116,104,32,112,97,116,104,32,123,33,114, + 125,41,4,114,118,0,0,0,114,133,0,0,0,114,229,0, + 0,0,114,189,0,0,0,41,2,114,104,0,0,0,114,123, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,114,190,0,0,0,16,4,0,0,115,6,0,0,0, + 0,7,6,1,8,1,122,28,95,78,97,109,101,115,112,97, + 99,101,76,111,97,100,101,114,46,108,111,97,100,95,109,111, + 100,117,108,101,78,41,12,114,109,0,0,0,114,108,0,0, + 0,114,110,0,0,0,114,182,0,0,0,114,180,0,0,0, + 114,247,0,0,0,114,157,0,0,0,114,199,0,0,0,114, + 184,0,0,0,114,183,0,0,0,114,188,0,0,0,114,190, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,246,0,0,0,244,3,0,0, + 115,16,0,0,0,8,1,8,3,12,9,8,3,8,3,8, + 3,8,3,8,3,114,246,0,0,0,99,0,0,0,0,0, + 0,0,0,0,0,0,0,4,0,0,0,64,0,0,0,115, + 106,0,0,0,101,0,90,1,100,0,90,2,100,1,90,3, + 101,4,100,2,100,3,132,0,131,1,90,5,101,4,100,4, + 100,5,132,0,131,1,90,6,101,4,100,6,100,7,132,0, + 131,1,90,7,101,4,100,8,100,9,132,0,131,1,90,8, + 101,4,100,17,100,11,100,12,132,1,131,1,90,9,101,4, + 100,18,100,13,100,14,132,1,131,1,90,10,101,4,100,19, + 100,15,100,16,132,1,131,1,90,11,100,10,83,0,41,20, + 218,10,80,97,116,104,70,105,110,100,101,114,122,62,77,101, + 116,97,32,112,97,116,104,32,102,105,110,100,101,114,32,102, + 111,114,32,115,121,115,46,112,97,116,104,32,97,110,100,32, + 112,97,99,107,97,103,101,32,95,95,112,97,116,104,95,95, + 32,97,116,116,114,105,98,117,116,101,115,46,99,1,0,0, + 0,0,0,0,0,2,0,0,0,4,0,0,0,67,0,0, + 0,115,42,0,0,0,120,36,116,0,106,1,106,2,131,0, + 68,0,93,22,125,1,116,3,124,1,100,1,131,2,114,12, + 124,1,106,4,131,0,1,0,113,12,87,0,100,2,83,0, + 41,3,122,125,67,97,108,108,32,116,104,101,32,105,110,118, + 97,108,105,100,97,116,101,95,99,97,99,104,101,115,40,41, + 32,109,101,116,104,111,100,32,111,110,32,97,108,108,32,112, + 97,116,104,32,101,110,116,114,121,32,102,105,110,100,101,114, + 115,10,32,32,32,32,32,32,32,32,115,116,111,114,101,100, + 32,105,110,32,115,121,115,46,112,97,116,104,95,105,109,112, + 111,114,116,101,114,95,99,97,99,104,101,115,32,40,119,104, + 101,114,101,32,105,109,112,108,101,109,101,110,116,101,100,41, + 46,218,17,105,110,118,97,108,105,100,97,116,101,95,99,97, + 99,104,101,115,78,41,5,114,8,0,0,0,218,19,112,97, + 116,104,95,105,109,112,111,114,116,101,114,95,99,97,99,104, + 101,218,6,118,97,108,117,101,115,114,112,0,0,0,114,249, + 0,0,0,41,2,114,168,0,0,0,218,6,102,105,110,100, + 101,114,114,4,0,0,0,114,4,0,0,0,114,6,0,0, + 0,114,249,0,0,0,34,4,0,0,115,6,0,0,0,0, + 4,16,1,10,1,122,28,80,97,116,104,70,105,110,100,101, + 114,46,105,110,118,97,108,105,100,97,116,101,95,99,97,99, + 104,101,115,99,2,0,0,0,0,0,0,0,3,0,0,0, + 12,0,0,0,67,0,0,0,115,86,0,0,0,116,0,106, + 1,100,1,107,9,114,30,116,0,106,1,12,0,114,30,116, + 2,106,3,100,2,116,4,131,2,1,0,120,50,116,0,106, + 1,68,0,93,36,125,2,121,8,124,2,124,1,131,1,83, + 0,4,0,116,5,107,10,114,72,1,0,1,0,1,0,119, + 38,89,0,113,38,88,0,113,38,87,0,100,1,83,0,100, + 1,83,0,41,3,122,46,83,101,97,114,99,104,32,115,121, + 115,46,112,97,116,104,95,104,111,111,107,115,32,102,111,114, + 32,97,32,102,105,110,100,101,114,32,102,111,114,32,39,112, + 97,116,104,39,46,78,122,23,115,121,115,46,112,97,116,104, + 95,104,111,111,107,115,32,105,115,32,101,109,112,116,121,41, + 6,114,8,0,0,0,218,10,112,97,116,104,95,104,111,111, + 107,115,114,63,0,0,0,114,64,0,0,0,114,122,0,0, + 0,114,103,0,0,0,41,3,114,168,0,0,0,114,37,0, + 0,0,90,4,104,111,111,107,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,218,11,95,112,97,116,104,95,104, + 111,111,107,115,42,4,0,0,115,16,0,0,0,0,3,18, + 1,12,1,12,1,2,1,8,1,14,1,12,2,122,22,80, + 97,116,104,70,105,110,100,101,114,46,95,112,97,116,104,95, + 104,111,111,107,115,99,2,0,0,0,0,0,0,0,3,0, + 0,0,19,0,0,0,67,0,0,0,115,102,0,0,0,124, + 1,100,1,107,2,114,42,121,12,116,0,106,1,131,0,125, + 1,87,0,110,20,4,0,116,2,107,10,114,40,1,0,1, + 0,1,0,100,2,83,0,88,0,121,14,116,3,106,4,124, + 1,25,0,125,2,87,0,110,40,4,0,116,5,107,10,114, + 96,1,0,1,0,1,0,124,0,106,6,124,1,131,1,125, + 2,124,2,116,3,106,4,124,1,60,0,89,0,110,2,88, + 0,124,2,83,0,41,3,122,210,71,101,116,32,116,104,101, + 32,102,105,110,100,101,114,32,102,111,114,32,116,104,101,32, + 112,97,116,104,32,101,110,116,114,121,32,102,114,111,109,32, + 115,121,115,46,112,97,116,104,95,105,109,112,111,114,116,101, + 114,95,99,97,99,104,101,46,10,10,32,32,32,32,32,32, + 32,32,73,102,32,116,104,101,32,112,97,116,104,32,101,110, + 116,114,121,32,105,115,32,110,111,116,32,105,110,32,116,104, + 101,32,99,97,99,104,101,44,32,102,105,110,100,32,116,104, + 101,32,97,112,112,114,111,112,114,105,97,116,101,32,102,105, + 110,100,101,114,10,32,32,32,32,32,32,32,32,97,110,100, + 32,99,97,99,104,101,32,105,116,46,32,73,102,32,110,111, + 32,102,105,110,100,101,114,32,105,115,32,97,118,97,105,108, + 97,98,108,101,44,32,115,116,111,114,101,32,78,111,110,101, + 46,10,10,32,32,32,32,32,32,32,32,114,32,0,0,0, + 78,41,7,114,3,0,0,0,114,47,0,0,0,218,17,70, + 105,108,101,78,111,116,70,111,117,110,100,69,114,114,111,114, + 114,8,0,0,0,114,250,0,0,0,114,135,0,0,0,114, + 254,0,0,0,41,3,114,168,0,0,0,114,37,0,0,0, + 114,252,0,0,0,114,4,0,0,0,114,4,0,0,0,114, + 6,0,0,0,218,20,95,112,97,116,104,95,105,109,112,111, + 114,116,101,114,95,99,97,99,104,101,55,4,0,0,115,22, + 0,0,0,0,8,8,1,2,1,12,1,14,3,6,1,2, + 1,14,1,14,1,10,1,16,1,122,31,80,97,116,104,70, + 105,110,100,101,114,46,95,112,97,116,104,95,105,109,112,111, + 114,116,101,114,95,99,97,99,104,101,99,3,0,0,0,0, + 0,0,0,6,0,0,0,3,0,0,0,67,0,0,0,115, + 82,0,0,0,116,0,124,2,100,1,131,2,114,26,124,2, + 106,1,124,1,131,1,92,2,125,3,125,4,110,14,124,2, + 106,2,124,1,131,1,125,3,103,0,125,4,124,3,100,0, + 107,9,114,60,116,3,106,4,124,1,124,3,131,2,83,0, + 116,3,106,5,124,1,100,0,131,2,125,5,124,4,124,5, + 95,6,124,5,83,0,41,2,78,114,121,0,0,0,41,7, + 114,112,0,0,0,114,121,0,0,0,114,179,0,0,0,114, + 118,0,0,0,114,176,0,0,0,114,158,0,0,0,114,154, + 0,0,0,41,6,114,168,0,0,0,114,123,0,0,0,114, + 252,0,0,0,114,124,0,0,0,114,125,0,0,0,114,162, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,218,16,95,108,101,103,97,99,121,95,103,101,116,95, + 115,112,101,99,77,4,0,0,115,18,0,0,0,0,4,10, + 1,16,2,10,1,4,1,8,1,12,1,12,1,6,1,122, + 27,80,97,116,104,70,105,110,100,101,114,46,95,108,101,103, + 97,99,121,95,103,101,116,95,115,112,101,99,78,99,4,0, + 0,0,0,0,0,0,9,0,0,0,5,0,0,0,67,0, + 0,0,115,170,0,0,0,103,0,125,4,120,160,124,2,68, + 0,93,130,125,5,116,0,124,5,116,1,116,2,102,2,131, + 2,115,30,113,10,124,0,106,3,124,5,131,1,125,6,124, + 6,100,1,107,9,114,10,116,4,124,6,100,2,131,2,114, + 72,124,6,106,5,124,1,124,3,131,2,125,7,110,12,124, + 0,106,6,124,1,124,6,131,2,125,7,124,7,100,1,107, + 8,114,94,113,10,124,7,106,7,100,1,107,9,114,108,124, + 7,83,0,124,7,106,8,125,8,124,8,100,1,107,8,114, + 130,116,9,100,3,131,1,130,1,124,4,106,10,124,8,131, + 1,1,0,113,10,87,0,116,11,106,12,124,1,100,1,131, + 2,125,7,124,4,124,7,95,8,124,7,83,0,100,1,83, + 0,41,4,122,63,70,105,110,100,32,116,104,101,32,108,111, + 97,100,101,114,32,111,114,32,110,97,109,101,115,112,97,99, + 101,95,112,97,116,104,32,102,111,114,32,116,104,105,115,32, + 109,111,100,117,108,101,47,112,97,99,107,97,103,101,32,110, + 97,109,101,46,78,114,178,0,0,0,122,19,115,112,101,99, + 32,109,105,115,115,105,110,103,32,108,111,97,100,101,114,41, + 13,114,141,0,0,0,114,73,0,0,0,218,5,98,121,116, + 101,115,114,0,1,0,0,114,112,0,0,0,114,178,0,0, + 0,114,1,1,0,0,114,124,0,0,0,114,154,0,0,0, + 114,103,0,0,0,114,147,0,0,0,114,118,0,0,0,114, + 158,0,0,0,41,9,114,168,0,0,0,114,123,0,0,0, + 114,37,0,0,0,114,177,0,0,0,218,14,110,97,109,101, + 115,112,97,99,101,95,112,97,116,104,90,5,101,110,116,114, + 121,114,252,0,0,0,114,162,0,0,0,114,125,0,0,0, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, + 9,95,103,101,116,95,115,112,101,99,92,4,0,0,115,40, + 0,0,0,0,5,4,1,10,1,14,1,2,1,10,1,8, + 1,10,1,14,2,12,1,8,1,2,1,10,1,4,1,6, + 1,8,1,8,5,14,2,12,1,6,1,122,20,80,97,116, + 104,70,105,110,100,101,114,46,95,103,101,116,95,115,112,101, + 99,99,4,0,0,0,0,0,0,0,6,0,0,0,4,0, + 0,0,67,0,0,0,115,100,0,0,0,124,2,100,1,107, + 8,114,14,116,0,106,1,125,2,124,0,106,2,124,1,124, + 2,124,3,131,3,125,4,124,4,100,1,107,8,114,40,100, + 1,83,0,124,4,106,3,100,1,107,8,114,92,124,4,106, + 4,125,5,124,5,114,86,100,2,124,4,95,5,116,6,124, + 1,124,5,124,0,106,2,131,3,124,4,95,4,124,4,83, + 0,100,1,83,0,110,4,124,4,83,0,100,1,83,0,41, + 3,122,141,84,114,121,32,116,111,32,102,105,110,100,32,97, + 32,115,112,101,99,32,102,111,114,32,39,102,117,108,108,110, + 97,109,101,39,32,111,110,32,115,121,115,46,112,97,116,104, + 32,111,114,32,39,112,97,116,104,39,46,10,10,32,32,32, + 32,32,32,32,32,84,104,101,32,115,101,97,114,99,104,32, + 105,115,32,98,97,115,101,100,32,111,110,32,115,121,115,46, + 112,97,116,104,95,104,111,111,107,115,32,97,110,100,32,115, + 121,115,46,112,97,116,104,95,105,109,112,111,114,116,101,114, + 95,99,97,99,104,101,46,10,32,32,32,32,32,32,32,32, + 78,90,9,110,97,109,101,115,112,97,99,101,41,7,114,8, + 0,0,0,114,37,0,0,0,114,4,1,0,0,114,124,0, + 0,0,114,154,0,0,0,114,156,0,0,0,114,227,0,0, + 0,41,6,114,168,0,0,0,114,123,0,0,0,114,37,0, + 0,0,114,177,0,0,0,114,162,0,0,0,114,3,1,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,184,0,0,0,7,4,0,0,115,2,0,0,0,0,1, - 122,25,95,78,97,109,101,115,112,97,99,101,76,111,97,100, - 101,114,46,103,101,116,95,99,111,100,101,99,2,0,0,0, - 0,0,0,0,2,0,0,0,1,0,0,0,67,0,0,0, - 115,4,0,0,0,100,1,83,0,41,2,122,42,85,115,101, - 32,100,101,102,97,117,108,116,32,115,101,109,97,110,116,105, - 99,115,32,102,111,114,32,109,111,100,117,108,101,32,99,114, - 101,97,116,105,111,110,46,78,114,4,0,0,0,41,2,114, - 104,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,183,0,0,0,10,4,0, - 0,115,0,0,0,0,122,30,95,78,97,109,101,115,112,97, - 99,101,76,111,97,100,101,114,46,99,114,101,97,116,101,95, - 109,111,100,117,108,101,99,2,0,0,0,0,0,0,0,2, - 0,0,0,1,0,0,0,67,0,0,0,115,4,0,0,0, - 100,0,83,0,41,1,78,114,4,0,0,0,41,2,114,104, - 0,0,0,114,187,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,188,0,0,0,13,4,0,0, - 115,2,0,0,0,0,1,122,28,95,78,97,109,101,115,112, - 97,99,101,76,111,97,100,101,114,46,101,120,101,99,95,109, - 111,100,117,108,101,99,2,0,0,0,0,0,0,0,2,0, - 0,0,3,0,0,0,67,0,0,0,115,26,0,0,0,116, - 0,106,1,100,1,124,0,106,2,131,2,1,0,116,0,106, - 3,124,0,124,1,131,2,83,0,41,2,122,98,76,111,97, - 100,32,97,32,110,97,109,101,115,112,97,99,101,32,109,111, - 100,117,108,101,46,10,10,32,32,32,32,32,32,32,32,84, - 104,105,115,32,109,101,116,104,111,100,32,105,115,32,100,101, - 112,114,101,99,97,116,101,100,46,32,32,85,115,101,32,101, - 120,101,99,95,109,111,100,117,108,101,40,41,32,105,110,115, - 116,101,97,100,46,10,10,32,32,32,32,32,32,32,32,122, - 38,110,97,109,101,115,112,97,99,101,32,109,111,100,117,108, - 101,32,108,111,97,100,101,100,32,119,105,116,104,32,112,97, - 116,104,32,123,33,114,125,41,4,114,118,0,0,0,114,133, - 0,0,0,114,229,0,0,0,114,189,0,0,0,41,2,114, - 104,0,0,0,114,123,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,190,0,0,0,16,4,0, - 0,115,6,0,0,0,0,7,6,1,8,1,122,28,95,78, - 97,109,101,115,112,97,99,101,76,111,97,100,101,114,46,108, - 111,97,100,95,109,111,100,117,108,101,78,41,12,114,109,0, - 0,0,114,108,0,0,0,114,110,0,0,0,114,182,0,0, - 0,114,180,0,0,0,114,247,0,0,0,114,157,0,0,0, - 114,199,0,0,0,114,184,0,0,0,114,183,0,0,0,114, - 188,0,0,0,114,190,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,114,246,0, - 0,0,244,3,0,0,115,16,0,0,0,8,1,8,3,12, - 9,8,3,8,3,8,3,8,3,8,3,114,246,0,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, - 0,64,0,0,0,115,106,0,0,0,101,0,90,1,100,0, - 90,2,100,1,90,3,101,4,100,2,100,3,132,0,131,1, - 90,5,101,4,100,4,100,5,132,0,131,1,90,6,101,4, - 100,6,100,7,132,0,131,1,90,7,101,4,100,8,100,9, - 132,0,131,1,90,8,101,4,100,17,100,11,100,12,132,1, - 131,1,90,9,101,4,100,18,100,13,100,14,132,1,131,1, - 90,10,101,4,100,19,100,15,100,16,132,1,131,1,90,11, - 100,10,83,0,41,20,218,10,80,97,116,104,70,105,110,100, - 101,114,122,62,77,101,116,97,32,112,97,116,104,32,102,105, - 110,100,101,114,32,102,111,114,32,115,121,115,46,112,97,116, - 104,32,97,110,100,32,112,97,99,107,97,103,101,32,95,95, - 112,97,116,104,95,95,32,97,116,116,114,105,98,117,116,101, - 115,46,99,1,0,0,0,0,0,0,0,2,0,0,0,4, - 0,0,0,67,0,0,0,115,42,0,0,0,120,36,116,0, - 106,1,106,2,131,0,68,0,93,22,125,1,116,3,124,1, - 100,1,131,2,114,12,124,1,106,4,131,0,1,0,113,12, - 87,0,100,2,83,0,41,3,122,125,67,97,108,108,32,116, - 104,101,32,105,110,118,97,108,105,100,97,116,101,95,99,97, - 99,104,101,115,40,41,32,109,101,116,104,111,100,32,111,110, - 32,97,108,108,32,112,97,116,104,32,101,110,116,114,121,32, - 102,105,110,100,101,114,115,10,32,32,32,32,32,32,32,32, - 115,116,111,114,101,100,32,105,110,32,115,121,115,46,112,97, - 116,104,95,105,109,112,111,114,116,101,114,95,99,97,99,104, - 101,115,32,40,119,104,101,114,101,32,105,109,112,108,101,109, - 101,110,116,101,100,41,46,218,17,105,110,118,97,108,105,100, - 97,116,101,95,99,97,99,104,101,115,78,41,5,114,8,0, - 0,0,218,19,112,97,116,104,95,105,109,112,111,114,116,101, - 114,95,99,97,99,104,101,218,6,118,97,108,117,101,115,114, - 112,0,0,0,114,249,0,0,0,41,2,114,168,0,0,0, - 218,6,102,105,110,100,101,114,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,34,4,0,0, - 115,6,0,0,0,0,4,16,1,10,1,122,28,80,97,116, - 104,70,105,110,100,101,114,46,105,110,118,97,108,105,100,97, - 116,101,95,99,97,99,104,101,115,99,2,0,0,0,0,0, - 0,0,3,0,0,0,12,0,0,0,67,0,0,0,115,86, - 0,0,0,116,0,106,1,100,1,107,9,114,30,116,0,106, - 1,12,0,114,30,116,2,106,3,100,2,116,4,131,2,1, - 0,120,50,116,0,106,1,68,0,93,36,125,2,121,8,124, - 2,124,1,131,1,83,0,4,0,116,5,107,10,114,72,1, - 0,1,0,1,0,119,38,89,0,113,38,88,0,113,38,87, - 0,100,1,83,0,100,1,83,0,41,3,122,46,83,101,97, - 114,99,104,32,115,121,115,46,112,97,116,104,95,104,111,111, - 107,115,32,102,111,114,32,97,32,102,105,110,100,101,114,32, - 102,111,114,32,39,112,97,116,104,39,46,78,122,23,115,121, - 115,46,112,97,116,104,95,104,111,111,107,115,32,105,115,32, - 101,109,112,116,121,41,6,114,8,0,0,0,218,10,112,97, - 116,104,95,104,111,111,107,115,114,63,0,0,0,114,64,0, - 0,0,114,122,0,0,0,114,103,0,0,0,41,3,114,168, - 0,0,0,114,37,0,0,0,90,4,104,111,111,107,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,218,11,95, - 112,97,116,104,95,104,111,111,107,115,42,4,0,0,115,16, - 0,0,0,0,3,18,1,12,1,12,1,2,1,8,1,14, - 1,12,2,122,22,80,97,116,104,70,105,110,100,101,114,46, - 95,112,97,116,104,95,104,111,111,107,115,99,2,0,0,0, - 0,0,0,0,3,0,0,0,19,0,0,0,67,0,0,0, - 115,102,0,0,0,124,1,100,1,107,2,114,42,121,12,116, - 0,106,1,131,0,125,1,87,0,110,20,4,0,116,2,107, - 10,114,40,1,0,1,0,1,0,100,2,83,0,88,0,121, - 14,116,3,106,4,124,1,25,0,125,2,87,0,110,40,4, - 0,116,5,107,10,114,96,1,0,1,0,1,0,124,0,106, - 6,124,1,131,1,125,2,124,2,116,3,106,4,124,1,60, - 0,89,0,110,2,88,0,124,2,83,0,41,3,122,210,71, - 101,116,32,116,104,101,32,102,105,110,100,101,114,32,102,111, - 114,32,116,104,101,32,112,97,116,104,32,101,110,116,114,121, - 32,102,114,111,109,32,115,121,115,46,112,97,116,104,95,105, - 109,112,111,114,116,101,114,95,99,97,99,104,101,46,10,10, - 32,32,32,32,32,32,32,32,73,102,32,116,104,101,32,112, - 97,116,104,32,101,110,116,114,121,32,105,115,32,110,111,116, - 32,105,110,32,116,104,101,32,99,97,99,104,101,44,32,102, - 105,110,100,32,116,104,101,32,97,112,112,114,111,112,114,105, - 97,116,101,32,102,105,110,100,101,114,10,32,32,32,32,32, - 32,32,32,97,110,100,32,99,97,99,104,101,32,105,116,46, - 32,73,102,32,110,111,32,102,105,110,100,101,114,32,105,115, - 32,97,118,97,105,108,97,98,108,101,44,32,115,116,111,114, - 101,32,78,111,110,101,46,10,10,32,32,32,32,32,32,32, - 32,114,32,0,0,0,78,41,7,114,3,0,0,0,114,47, - 0,0,0,218,17,70,105,108,101,78,111,116,70,111,117,110, - 100,69,114,114,111,114,114,8,0,0,0,114,250,0,0,0, - 114,135,0,0,0,114,254,0,0,0,41,3,114,168,0,0, - 0,114,37,0,0,0,114,252,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,218,20,95,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 55,4,0,0,115,22,0,0,0,0,8,8,1,2,1,12, - 1,14,3,6,1,2,1,14,1,14,1,10,1,16,1,122, - 31,80,97,116,104,70,105,110,100,101,114,46,95,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 99,3,0,0,0,0,0,0,0,6,0,0,0,3,0,0, - 0,67,0,0,0,115,82,0,0,0,116,0,124,2,100,1, - 131,2,114,26,124,2,106,1,124,1,131,1,92,2,125,3, - 125,4,110,14,124,2,106,2,124,1,131,1,125,3,103,0, - 125,4,124,3,100,0,107,9,114,60,116,3,106,4,124,1, - 124,3,131,2,83,0,116,3,106,5,124,1,100,0,131,2, - 125,5,124,4,124,5,95,6,124,5,83,0,41,2,78,114, - 121,0,0,0,41,7,114,112,0,0,0,114,121,0,0,0, - 114,179,0,0,0,114,118,0,0,0,114,176,0,0,0,114, - 158,0,0,0,114,154,0,0,0,41,6,114,168,0,0,0, - 114,123,0,0,0,114,252,0,0,0,114,124,0,0,0,114, - 125,0,0,0,114,162,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,218,16,95,108,101,103,97,99, - 121,95,103,101,116,95,115,112,101,99,77,4,0,0,115,18, - 0,0,0,0,4,10,1,16,2,10,1,4,1,8,1,12, - 1,12,1,6,1,122,27,80,97,116,104,70,105,110,100,101, - 114,46,95,108,101,103,97,99,121,95,103,101,116,95,115,112, - 101,99,78,99,4,0,0,0,0,0,0,0,9,0,0,0, - 5,0,0,0,67,0,0,0,115,170,0,0,0,103,0,125, - 4,120,160,124,2,68,0,93,130,125,5,116,0,124,5,116, - 1,116,2,102,2,131,2,115,30,113,10,124,0,106,3,124, - 5,131,1,125,6,124,6,100,1,107,9,114,10,116,4,124, - 6,100,2,131,2,114,72,124,6,106,5,124,1,124,3,131, - 2,125,7,110,12,124,0,106,6,124,1,124,6,131,2,125, - 7,124,7,100,1,107,8,114,94,113,10,124,7,106,7,100, - 1,107,9,114,108,124,7,83,0,124,7,106,8,125,8,124, - 8,100,1,107,8,114,130,116,9,100,3,131,1,130,1,124, - 4,106,10,124,8,131,1,1,0,113,10,87,0,116,11,106, - 12,124,1,100,1,131,2,125,7,124,4,124,7,95,8,124, - 7,83,0,100,1,83,0,41,4,122,63,70,105,110,100,32, - 116,104,101,32,108,111,97,100,101,114,32,111,114,32,110,97, - 109,101,115,112,97,99,101,95,112,97,116,104,32,102,111,114, - 32,116,104,105,115,32,109,111,100,117,108,101,47,112,97,99, - 107,97,103,101,32,110,97,109,101,46,78,114,178,0,0,0, - 122,19,115,112,101,99,32,109,105,115,115,105,110,103,32,108, - 111,97,100,101,114,41,13,114,141,0,0,0,114,73,0,0, - 0,218,5,98,121,116,101,115,114,0,1,0,0,114,112,0, - 0,0,114,178,0,0,0,114,1,1,0,0,114,124,0,0, - 0,114,154,0,0,0,114,103,0,0,0,114,147,0,0,0, - 114,118,0,0,0,114,158,0,0,0,41,9,114,168,0,0, - 0,114,123,0,0,0,114,37,0,0,0,114,177,0,0,0, - 218,14,110,97,109,101,115,112,97,99,101,95,112,97,116,104, - 90,5,101,110,116,114,121,114,252,0,0,0,114,162,0,0, - 0,114,125,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,6,0,0,0,218,9,95,103,101,116,95,115,112,101,99, - 92,4,0,0,115,40,0,0,0,0,5,4,1,10,1,14, - 1,2,1,10,1,8,1,10,1,14,2,12,1,8,1,2, - 1,10,1,4,1,6,1,8,1,8,5,14,2,12,1,6, - 1,122,20,80,97,116,104,70,105,110,100,101,114,46,95,103, - 101,116,95,115,112,101,99,99,4,0,0,0,0,0,0,0, - 6,0,0,0,4,0,0,0,67,0,0,0,115,104,0,0, - 0,124,2,100,1,107,8,114,14,116,0,106,1,125,2,124, - 0,106,2,124,1,124,2,124,3,131,3,125,4,124,4,100, - 1,107,8,114,42,100,1,83,0,110,58,124,4,106,3,100, - 1,107,8,114,96,124,4,106,4,125,5,124,5,114,90,100, - 2,124,4,95,5,116,6,124,1,124,5,124,0,106,2,131, - 3,124,4,95,4,124,4,83,0,113,100,100,1,83,0,110, - 4,124,4,83,0,100,1,83,0,41,3,122,141,84,114,121, - 32,116,111,32,102,105,110,100,32,97,32,115,112,101,99,32, - 102,111,114,32,39,102,117,108,108,110,97,109,101,39,32,111, - 110,32,115,121,115,46,112,97,116,104,32,111,114,32,39,112, - 97,116,104,39,46,10,10,32,32,32,32,32,32,32,32,84, - 104,101,32,115,101,97,114,99,104,32,105,115,32,98,97,115, - 101,100,32,111,110,32,115,121,115,46,112,97,116,104,95,104, - 111,111,107,115,32,97,110,100,32,115,121,115,46,112,97,116, - 104,95,105,109,112,111,114,116,101,114,95,99,97,99,104,101, - 46,10,32,32,32,32,32,32,32,32,78,90,9,110,97,109, - 101,115,112,97,99,101,41,7,114,8,0,0,0,114,37,0, - 0,0,114,4,1,0,0,114,124,0,0,0,114,154,0,0, - 0,114,156,0,0,0,114,227,0,0,0,41,6,114,168,0, - 0,0,114,123,0,0,0,114,37,0,0,0,114,177,0,0, - 0,114,162,0,0,0,114,3,1,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,124, - 4,0,0,115,26,0,0,0,0,6,8,1,6,1,14,1, - 8,1,6,1,10,1,6,1,4,3,6,1,16,1,6,2, - 6,2,122,20,80,97,116,104,70,105,110,100,101,114,46,102, - 105,110,100,95,115,112,101,99,99,3,0,0,0,0,0,0, - 0,4,0,0,0,3,0,0,0,67,0,0,0,115,30,0, - 0,0,124,0,106,0,124,1,124,2,131,2,125,3,124,3, - 100,1,107,8,114,24,100,1,83,0,124,3,106,1,83,0, - 41,2,122,170,102,105,110,100,32,116,104,101,32,109,111,100, - 117,108,101,32,111,110,32,115,121,115,46,112,97,116,104,32, - 111,114,32,39,112,97,116,104,39,32,98,97,115,101,100,32, - 111,110,32,115,121,115,46,112,97,116,104,95,104,111,111,107, - 115,32,97,110,100,10,32,32,32,32,32,32,32,32,115,121, - 115,46,112,97,116,104,95,105,109,112,111,114,116,101,114,95, - 99,97,99,104,101,46,10,10,32,32,32,32,32,32,32,32, - 84,104,105,115,32,109,101,116,104,111,100,32,105,115,32,100, - 101,112,114,101,99,97,116,101,100,46,32,32,85,115,101,32, - 102,105,110,100,95,115,112,101,99,40,41,32,105,110,115,116, - 101,97,100,46,10,10,32,32,32,32,32,32,32,32,78,41, - 2,114,178,0,0,0,114,124,0,0,0,41,4,114,168,0, - 0,0,114,123,0,0,0,114,37,0,0,0,114,162,0,0, + 114,178,0,0,0,124,4,0,0,115,26,0,0,0,0,6, + 8,1,6,1,14,1,8,1,4,1,10,1,6,1,4,3, + 6,1,16,1,4,2,6,2,122,20,80,97,116,104,70,105, + 110,100,101,114,46,102,105,110,100,95,115,112,101,99,99,3, + 0,0,0,0,0,0,0,4,0,0,0,3,0,0,0,67, + 0,0,0,115,30,0,0,0,124,0,106,0,124,1,124,2, + 131,2,125,3,124,3,100,1,107,8,114,24,100,1,83,0, + 124,3,106,1,83,0,41,2,122,170,102,105,110,100,32,116, + 104,101,32,109,111,100,117,108,101,32,111,110,32,115,121,115, + 46,112,97,116,104,32,111,114,32,39,112,97,116,104,39,32, + 98,97,115,101,100,32,111,110,32,115,121,115,46,112,97,116, + 104,95,104,111,111,107,115,32,97,110,100,10,32,32,32,32, + 32,32,32,32,115,121,115,46,112,97,116,104,95,105,109,112, + 111,114,116,101,114,95,99,97,99,104,101,46,10,10,32,32, + 32,32,32,32,32,32,84,104,105,115,32,109,101,116,104,111, + 100,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46, + 32,32,85,115,101,32,102,105,110,100,95,115,112,101,99,40, + 41,32,105,110,115,116,101,97,100,46,10,10,32,32,32,32, + 32,32,32,32,78,41,2,114,178,0,0,0,114,124,0,0, + 0,41,4,114,168,0,0,0,114,123,0,0,0,114,37,0, + 0,0,114,162,0,0,0,114,4,0,0,0,114,4,0,0, + 0,114,6,0,0,0,114,179,0,0,0,148,4,0,0,115, + 8,0,0,0,0,8,12,1,8,1,4,1,122,22,80,97, + 116,104,70,105,110,100,101,114,46,102,105,110,100,95,109,111, + 100,117,108,101,41,1,78,41,2,78,78,41,1,78,41,12, + 114,109,0,0,0,114,108,0,0,0,114,110,0,0,0,114, + 111,0,0,0,114,180,0,0,0,114,249,0,0,0,114,254, + 0,0,0,114,0,1,0,0,114,1,1,0,0,114,4,1, + 0,0,114,178,0,0,0,114,179,0,0,0,114,4,0,0, 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, - 114,179,0,0,0,148,4,0,0,115,8,0,0,0,0,8, - 12,1,8,1,4,1,122,22,80,97,116,104,70,105,110,100, - 101,114,46,102,105,110,100,95,109,111,100,117,108,101,41,1, - 78,41,2,78,78,41,1,78,41,12,114,109,0,0,0,114, - 108,0,0,0,114,110,0,0,0,114,111,0,0,0,114,180, - 0,0,0,114,249,0,0,0,114,254,0,0,0,114,0,1, - 0,0,114,1,1,0,0,114,4,1,0,0,114,178,0,0, - 0,114,179,0,0,0,114,4,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,248,0,0,0,30, - 4,0,0,115,22,0,0,0,8,2,4,2,12,8,12,13, - 12,22,12,15,2,1,12,31,2,1,12,23,2,1,114,248, - 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0, - 3,0,0,0,64,0,0,0,115,90,0,0,0,101,0,90, - 1,100,0,90,2,100,1,90,3,100,2,100,3,132,0,90, - 4,100,4,100,5,132,0,90,5,101,6,90,7,100,6,100, - 7,132,0,90,8,100,8,100,9,132,0,90,9,100,19,100, - 11,100,12,132,1,90,10,100,13,100,14,132,0,90,11,101, - 12,100,15,100,16,132,0,131,1,90,13,100,17,100,18,132, - 0,90,14,100,10,83,0,41,20,218,10,70,105,108,101,70, - 105,110,100,101,114,122,172,70,105,108,101,45,98,97,115,101, - 100,32,102,105,110,100,101,114,46,10,10,32,32,32,32,73, - 110,116,101,114,97,99,116,105,111,110,115,32,119,105,116,104, - 32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109, - 32,97,114,101,32,99,97,99,104,101,100,32,102,111,114,32, - 112,101,114,102,111,114,109,97,110,99,101,44,32,98,101,105, - 110,103,10,32,32,32,32,114,101,102,114,101,115,104,101,100, - 32,119,104,101,110,32,116,104,101,32,100,105,114,101,99,116, - 111,114,121,32,116,104,101,32,102,105,110,100,101,114,32,105, - 115,32,104,97,110,100,108,105,110,103,32,104,97,115,32,98, - 101,101,110,32,109,111,100,105,102,105,101,100,46,10,10,32, - 32,32,32,99,2,0,0,0,0,0,0,0,5,0,0,0, - 5,0,0,0,7,0,0,0,115,88,0,0,0,103,0,125, - 3,120,40,124,2,68,0,93,32,92,2,137,0,125,4,124, - 3,106,0,135,0,102,1,100,1,100,2,132,8,124,4,68, - 0,131,1,131,1,1,0,113,10,87,0,124,3,124,0,95, - 1,124,1,112,58,100,3,124,0,95,2,100,6,124,0,95, - 3,116,4,131,0,124,0,95,5,116,4,131,0,124,0,95, - 6,100,5,83,0,41,7,122,154,73,110,105,116,105,97,108, - 105,122,101,32,119,105,116,104,32,116,104,101,32,112,97,116, - 104,32,116,111,32,115,101,97,114,99,104,32,111,110,32,97, - 110,100,32,97,32,118,97,114,105,97,98,108,101,32,110,117, - 109,98,101,114,32,111,102,10,32,32,32,32,32,32,32,32, - 50,45,116,117,112,108,101,115,32,99,111,110,116,97,105,110, - 105,110,103,32,116,104,101,32,108,111,97,100,101,114,32,97, - 110,100,32,116,104,101,32,102,105,108,101,32,115,117,102,102, - 105,120,101,115,32,116,104,101,32,108,111,97,100,101,114,10, - 32,32,32,32,32,32,32,32,114,101,99,111,103,110,105,122, - 101,115,46,99,1,0,0,0,0,0,0,0,2,0,0,0, - 3,0,0,0,51,0,0,0,115,22,0,0,0,124,0,93, - 14,125,1,124,1,136,0,102,2,86,0,1,0,113,2,100, - 0,83,0,41,1,78,114,4,0,0,0,41,2,114,24,0, - 0,0,114,222,0,0,0,41,1,114,124,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,224,0,0,0,177,4,0, - 0,115,2,0,0,0,4,0,122,38,70,105,108,101,70,105, - 110,100,101,114,46,95,95,105,110,105,116,95,95,46,60,108, - 111,99,97,108,115,62,46,60,103,101,110,101,120,112,114,62, - 114,61,0,0,0,114,31,0,0,0,78,114,91,0,0,0, - 41,7,114,147,0,0,0,218,8,95,108,111,97,100,101,114, - 115,114,37,0,0,0,218,11,95,112,97,116,104,95,109,116, - 105,109,101,218,3,115,101,116,218,11,95,112,97,116,104,95, - 99,97,99,104,101,218,19,95,114,101,108,97,120,101,100,95, - 112,97,116,104,95,99,97,99,104,101,41,5,114,104,0,0, - 0,114,37,0,0,0,218,14,108,111,97,100,101,114,95,100, - 101,116,97,105,108,115,90,7,108,111,97,100,101,114,115,114, - 164,0,0,0,114,4,0,0,0,41,1,114,124,0,0,0, - 114,6,0,0,0,114,182,0,0,0,171,4,0,0,115,16, - 0,0,0,0,4,4,1,14,1,28,1,6,2,10,1,6, - 1,8,1,122,19,70,105,108,101,70,105,110,100,101,114,46, - 95,95,105,110,105,116,95,95,99,1,0,0,0,0,0,0, - 0,1,0,0,0,2,0,0,0,67,0,0,0,115,10,0, - 0,0,100,3,124,0,95,0,100,2,83,0,41,4,122,31, - 73,110,118,97,108,105,100,97,116,101,32,116,104,101,32,100, - 105,114,101,99,116,111,114,121,32,109,116,105,109,101,46,114, - 31,0,0,0,78,114,91,0,0,0,41,1,114,7,1,0, - 0,41,1,114,104,0,0,0,114,4,0,0,0,114,4,0, - 0,0,114,6,0,0,0,114,249,0,0,0,185,4,0,0, - 115,2,0,0,0,0,2,122,28,70,105,108,101,70,105,110, - 100,101,114,46,105,110,118,97,108,105,100,97,116,101,95,99, - 97,99,104,101,115,99,2,0,0,0,0,0,0,0,3,0, - 0,0,2,0,0,0,67,0,0,0,115,42,0,0,0,124, - 0,106,0,124,1,131,1,125,2,124,2,100,1,107,8,114, - 26,100,1,103,0,102,2,83,0,124,2,106,1,124,2,106, - 2,112,38,103,0,102,2,83,0,41,2,122,197,84,114,121, - 32,116,111,32,102,105,110,100,32,97,32,108,111,97,100,101, - 114,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102, - 105,101,100,32,109,111,100,117,108,101,44,32,111,114,32,116, - 104,101,32,110,97,109,101,115,112,97,99,101,10,32,32,32, - 32,32,32,32,32,112,97,99,107,97,103,101,32,112,111,114, - 116,105,111,110,115,46,32,82,101,116,117,114,110,115,32,40, - 108,111,97,100,101,114,44,32,108,105,115,116,45,111,102,45, - 112,111,114,116,105,111,110,115,41,46,10,10,32,32,32,32, - 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32, - 105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,32, - 85,115,101,32,102,105,110,100,95,115,112,101,99,40,41,32, - 105,110,115,116,101,97,100,46,10,10,32,32,32,32,32,32, - 32,32,78,41,3,114,178,0,0,0,114,124,0,0,0,114, - 154,0,0,0,41,3,114,104,0,0,0,114,123,0,0,0, - 114,162,0,0,0,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,121,0,0,0,191,4,0,0,115,8,0, - 0,0,0,7,10,1,8,1,8,1,122,22,70,105,108,101, - 70,105,110,100,101,114,46,102,105,110,100,95,108,111,97,100, - 101,114,99,6,0,0,0,0,0,0,0,7,0,0,0,6, - 0,0,0,67,0,0,0,115,26,0,0,0,124,1,124,2, - 124,3,131,2,125,6,116,0,124,2,124,3,124,6,124,4, - 100,1,141,4,83,0,41,2,78,41,2,114,124,0,0,0, - 114,154,0,0,0,41,1,114,165,0,0,0,41,7,114,104, - 0,0,0,114,163,0,0,0,114,123,0,0,0,114,37,0, - 0,0,90,4,115,109,115,108,114,177,0,0,0,114,124,0, - 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,4,1,0,0,203,4,0,0,115,6,0,0,0,0, - 1,10,1,8,1,122,20,70,105,108,101,70,105,110,100,101, - 114,46,95,103,101,116,95,115,112,101,99,78,99,3,0,0, - 0,0,0,0,0,14,0,0,0,15,0,0,0,67,0,0, - 0,115,98,1,0,0,100,1,125,3,124,1,106,0,100,2, - 131,1,100,3,25,0,125,4,121,24,116,1,124,0,106,2, - 112,34,116,3,106,4,131,0,131,1,106,5,125,5,87,0, - 110,24,4,0,116,6,107,10,114,66,1,0,1,0,1,0, - 100,10,125,5,89,0,110,2,88,0,124,5,124,0,106,7, - 107,3,114,92,124,0,106,8,131,0,1,0,124,5,124,0, - 95,7,116,9,131,0,114,114,124,0,106,10,125,6,124,4, - 106,11,131,0,125,7,110,10,124,0,106,12,125,6,124,4, - 125,7,124,7,124,6,107,6,114,218,116,13,124,0,106,2, - 124,4,131,2,125,8,120,72,124,0,106,14,68,0,93,54, - 92,2,125,9,125,10,100,5,124,9,23,0,125,11,116,13, - 124,8,124,11,131,2,125,12,116,15,124,12,131,1,114,152, - 124,0,106,16,124,10,124,1,124,12,124,8,103,1,124,2, - 131,5,83,0,113,152,87,0,116,17,124,8,131,1,125,3, - 120,88,124,0,106,14,68,0,93,78,92,2,125,9,125,10, - 116,13,124,0,106,2,124,4,124,9,23,0,131,2,125,12, - 116,18,106,19,100,6,124,12,100,3,100,7,141,3,1,0, - 124,7,124,9,23,0,124,6,107,6,114,226,116,15,124,12, - 131,1,114,226,124,0,106,16,124,10,124,1,124,12,100,8, - 124,2,131,5,83,0,113,226,87,0,124,3,144,1,114,94, - 116,18,106,19,100,9,124,8,131,2,1,0,116,18,106,20, - 124,1,100,8,131,2,125,13,124,8,103,1,124,13,95,21, - 124,13,83,0,100,8,83,0,41,11,122,111,84,114,121,32, - 116,111,32,102,105,110,100,32,97,32,115,112,101,99,32,102, - 111,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100, - 32,109,111,100,117,108,101,46,10,10,32,32,32,32,32,32, - 32,32,82,101,116,117,114,110,115,32,116,104,101,32,109,97, - 116,99,104,105,110,103,32,115,112,101,99,44,32,111,114,32, - 78,111,110,101,32,105,102,32,110,111,116,32,102,111,117,110, - 100,46,10,32,32,32,32,32,32,32,32,70,114,61,0,0, - 0,114,59,0,0,0,114,31,0,0,0,114,182,0,0,0, - 122,9,116,114,121,105,110,103,32,123,125,41,1,90,9,118, - 101,114,98,111,115,105,116,121,78,122,25,112,111,115,115,105, - 98,108,101,32,110,97,109,101,115,112,97,99,101,32,102,111, - 114,32,123,125,114,91,0,0,0,41,22,114,34,0,0,0, - 114,41,0,0,0,114,37,0,0,0,114,3,0,0,0,114, - 47,0,0,0,114,216,0,0,0,114,42,0,0,0,114,7, - 1,0,0,218,11,95,102,105,108,108,95,99,97,99,104,101, - 114,7,0,0,0,114,10,1,0,0,114,92,0,0,0,114, - 9,1,0,0,114,30,0,0,0,114,6,1,0,0,114,46, - 0,0,0,114,4,1,0,0,114,48,0,0,0,114,118,0, - 0,0,114,133,0,0,0,114,158,0,0,0,114,154,0,0, - 0,41,14,114,104,0,0,0,114,123,0,0,0,114,177,0, - 0,0,90,12,105,115,95,110,97,109,101,115,112,97,99,101, - 90,11,116,97,105,108,95,109,111,100,117,108,101,114,130,0, - 0,0,90,5,99,97,99,104,101,90,12,99,97,99,104,101, - 95,109,111,100,117,108,101,90,9,98,97,115,101,95,112,97, - 116,104,114,222,0,0,0,114,163,0,0,0,90,13,105,110, - 105,116,95,102,105,108,101,110,97,109,101,90,9,102,117,108, - 108,95,112,97,116,104,114,162,0,0,0,114,4,0,0,0, - 114,4,0,0,0,114,6,0,0,0,114,178,0,0,0,208, - 4,0,0,115,70,0,0,0,0,5,4,1,14,1,2,1, - 24,1,14,1,10,1,10,1,8,1,6,2,6,1,6,1, - 10,2,6,1,4,2,8,1,12,1,16,1,8,1,10,1, - 8,1,24,4,8,2,16,1,16,1,16,1,12,1,8,1, - 10,1,12,1,6,1,12,1,12,1,8,1,4,1,122,20, - 70,105,108,101,70,105,110,100,101,114,46,102,105,110,100,95, - 115,112,101,99,99,1,0,0,0,0,0,0,0,9,0,0, - 0,13,0,0,0,67,0,0,0,115,194,0,0,0,124,0, - 106,0,125,1,121,22,116,1,106,2,124,1,112,22,116,1, - 106,3,131,0,131,1,125,2,87,0,110,30,4,0,116,4, - 116,5,116,6,102,3,107,10,114,58,1,0,1,0,1,0, - 103,0,125,2,89,0,110,2,88,0,116,7,106,8,106,9, - 100,1,131,1,115,84,116,10,124,2,131,1,124,0,95,11, - 110,78,116,10,131,0,125,3,120,64,124,2,68,0,93,56, - 125,4,124,4,106,12,100,2,131,1,92,3,125,5,125,6, - 125,7,124,6,114,138,100,3,106,13,124,5,124,7,106,14, - 131,0,131,2,125,8,110,4,124,5,125,8,124,3,106,15, - 124,8,131,1,1,0,113,96,87,0,124,3,124,0,95,11, - 116,7,106,8,106,9,116,16,131,1,114,190,100,4,100,5, - 132,0,124,2,68,0,131,1,124,0,95,17,100,6,83,0, - 41,7,122,68,70,105,108,108,32,116,104,101,32,99,97,99, - 104,101,32,111,102,32,112,111,116,101,110,116,105,97,108,32, - 109,111,100,117,108,101,115,32,97,110,100,32,112,97,99,107, - 97,103,101,115,32,102,111,114,32,116,104,105,115,32,100,105, - 114,101,99,116,111,114,121,46,114,0,0,0,0,114,61,0, - 0,0,122,5,123,125,46,123,125,99,1,0,0,0,0,0, - 0,0,2,0,0,0,3,0,0,0,83,0,0,0,115,20, - 0,0,0,104,0,124,0,93,12,125,1,124,1,106,0,131, - 0,146,2,113,4,83,0,114,4,0,0,0,41,1,114,92, - 0,0,0,41,2,114,24,0,0,0,90,2,102,110,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,250,9,60, - 115,101,116,99,111,109,112,62,29,5,0,0,115,2,0,0, - 0,6,0,122,41,70,105,108,101,70,105,110,100,101,114,46, - 95,102,105,108,108,95,99,97,99,104,101,46,60,108,111,99, - 97,108,115,62,46,60,115,101,116,99,111,109,112,62,78,41, - 18,114,37,0,0,0,114,3,0,0,0,90,7,108,105,115, - 116,100,105,114,114,47,0,0,0,114,255,0,0,0,218,15, - 80,101,114,109,105,115,115,105,111,110,69,114,114,111,114,218, - 18,78,111,116,65,68,105,114,101,99,116,111,114,121,69,114, - 114,111,114,114,8,0,0,0,114,9,0,0,0,114,10,0, - 0,0,114,8,1,0,0,114,9,1,0,0,114,87,0,0, - 0,114,50,0,0,0,114,92,0,0,0,218,3,97,100,100, - 114,11,0,0,0,114,10,1,0,0,41,9,114,104,0,0, - 0,114,37,0,0,0,90,8,99,111,110,116,101,110,116,115, - 90,21,108,111,119,101,114,95,115,117,102,102,105,120,95,99, - 111,110,116,101,110,116,115,114,244,0,0,0,114,102,0,0, - 0,114,234,0,0,0,114,222,0,0,0,90,8,110,101,119, - 95,110,97,109,101,114,4,0,0,0,114,4,0,0,0,114, - 6,0,0,0,114,12,1,0,0,0,5,0,0,115,34,0, - 0,0,0,2,6,1,2,1,22,1,20,3,10,3,12,1, - 12,7,6,1,10,1,16,1,4,1,18,2,4,1,14,1, - 6,1,12,1,122,22,70,105,108,101,70,105,110,100,101,114, - 46,95,102,105,108,108,95,99,97,99,104,101,99,1,0,0, - 0,0,0,0,0,3,0,0,0,3,0,0,0,7,0,0, - 0,115,18,0,0,0,135,0,135,1,102,2,100,1,100,2, - 132,8,125,2,124,2,83,0,41,3,97,20,1,0,0,65, - 32,99,108,97,115,115,32,109,101,116,104,111,100,32,119,104, - 105,99,104,32,114,101,116,117,114,110,115,32,97,32,99,108, - 111,115,117,114,101,32,116,111,32,117,115,101,32,111,110,32, - 115,121,115,46,112,97,116,104,95,104,111,111,107,10,32,32, - 32,32,32,32,32,32,119,104,105,99,104,32,119,105,108,108, - 32,114,101,116,117,114,110,32,97,110,32,105,110,115,116,97, - 110,99,101,32,117,115,105,110,103,32,116,104,101,32,115,112, - 101,99,105,102,105,101,100,32,108,111,97,100,101,114,115,32, - 97,110,100,32,116,104,101,32,112,97,116,104,10,32,32,32, - 32,32,32,32,32,99,97,108,108,101,100,32,111,110,32,116, - 104,101,32,99,108,111,115,117,114,101,46,10,10,32,32,32, - 32,32,32,32,32,73,102,32,116,104,101,32,112,97,116,104, - 32,99,97,108,108,101,100,32,111,110,32,116,104,101,32,99, - 108,111,115,117,114,101,32,105,115,32,110,111,116,32,97,32, - 100,105,114,101,99,116,111,114,121,44,32,73,109,112,111,114, - 116,69,114,114,111,114,32,105,115,10,32,32,32,32,32,32, - 32,32,114,97,105,115,101,100,46,10,10,32,32,32,32,32, - 32,32,32,99,1,0,0,0,0,0,0,0,1,0,0,0, - 4,0,0,0,19,0,0,0,115,34,0,0,0,116,0,124, - 0,131,1,115,20,116,1,100,1,124,0,100,2,141,2,130, - 1,136,0,124,0,102,1,136,1,158,2,142,0,83,0,41, - 3,122,45,80,97,116,104,32,104,111,111,107,32,102,111,114, - 32,105,109,112,111,114,116,108,105,98,46,109,97,99,104,105, - 110,101,114,121,46,70,105,108,101,70,105,110,100,101,114,46, - 122,30,111,110,108,121,32,100,105,114,101,99,116,111,114,105, - 101,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100, - 41,1,114,37,0,0,0,41,2,114,48,0,0,0,114,103, - 0,0,0,41,1,114,37,0,0,0,41,2,114,168,0,0, - 0,114,11,1,0,0,114,4,0,0,0,114,6,0,0,0, - 218,24,112,97,116,104,95,104,111,111,107,95,102,111,114,95, - 70,105,108,101,70,105,110,100,101,114,41,5,0,0,115,6, - 0,0,0,0,2,8,1,12,1,122,54,70,105,108,101,70, - 105,110,100,101,114,46,112,97,116,104,95,104,111,111,107,46, - 60,108,111,99,97,108,115,62,46,112,97,116,104,95,104,111, - 111,107,95,102,111,114,95,70,105,108,101,70,105,110,100,101, - 114,114,4,0,0,0,41,3,114,168,0,0,0,114,11,1, - 0,0,114,17,1,0,0,114,4,0,0,0,41,2,114,168, - 0,0,0,114,11,1,0,0,114,6,0,0,0,218,9,112, - 97,116,104,95,104,111,111,107,31,5,0,0,115,4,0,0, - 0,0,10,14,6,122,20,70,105,108,101,70,105,110,100,101, - 114,46,112,97,116,104,95,104,111,111,107,99,1,0,0,0, - 0,0,0,0,1,0,0,0,2,0,0,0,67,0,0,0, - 115,12,0,0,0,100,1,106,0,124,0,106,1,131,1,83, - 0,41,2,78,122,16,70,105,108,101,70,105,110,100,101,114, - 40,123,33,114,125,41,41,2,114,50,0,0,0,114,37,0, - 0,0,41,1,114,104,0,0,0,114,4,0,0,0,114,4, - 0,0,0,114,6,0,0,0,114,243,0,0,0,49,5,0, - 0,115,2,0,0,0,0,1,122,19,70,105,108,101,70,105, - 110,100,101,114,46,95,95,114,101,112,114,95,95,41,1,78, - 41,15,114,109,0,0,0,114,108,0,0,0,114,110,0,0, - 0,114,111,0,0,0,114,182,0,0,0,114,249,0,0,0, - 114,127,0,0,0,114,179,0,0,0,114,121,0,0,0,114, - 4,1,0,0,114,178,0,0,0,114,12,1,0,0,114,180, - 0,0,0,114,18,1,0,0,114,243,0,0,0,114,4,0, - 0,0,114,4,0,0,0,114,4,0,0,0,114,6,0,0, - 0,114,5,1,0,0,162,4,0,0,115,20,0,0,0,8, - 7,4,2,8,14,8,4,4,2,8,12,8,5,10,48,8, - 31,12,18,114,5,1,0,0,99,4,0,0,0,0,0,0, - 0,6,0,0,0,11,0,0,0,67,0,0,0,115,146,0, - 0,0,124,0,106,0,100,1,131,1,125,4,124,0,106,0, - 100,2,131,1,125,5,124,4,115,66,124,5,114,36,124,5, - 106,1,125,4,110,30,124,2,124,3,107,2,114,56,116,2, - 124,1,124,2,131,2,125,4,110,10,116,3,124,1,124,2, - 131,2,125,4,124,5,115,84,116,4,124,1,124,2,124,4, - 100,3,141,3,125,5,121,36,124,5,124,0,100,2,60,0, - 124,4,124,0,100,1,60,0,124,2,124,0,100,4,60,0, - 124,3,124,0,100,5,60,0,87,0,110,20,4,0,116,5, - 107,10,114,140,1,0,1,0,1,0,89,0,110,2,88,0, - 100,0,83,0,41,6,78,218,10,95,95,108,111,97,100,101, - 114,95,95,218,8,95,95,115,112,101,99,95,95,41,1,114, - 124,0,0,0,90,8,95,95,102,105,108,101,95,95,90,10, - 95,95,99,97,99,104,101,100,95,95,41,6,218,3,103,101, - 116,114,124,0,0,0,114,220,0,0,0,114,215,0,0,0, - 114,165,0,0,0,218,9,69,120,99,101,112,116,105,111,110, - 41,6,90,2,110,115,114,102,0,0,0,90,8,112,97,116, - 104,110,97,109,101,90,9,99,112,97,116,104,110,97,109,101, - 114,124,0,0,0,114,162,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,218,14,95,102,105,120,95, - 117,112,95,109,111,100,117,108,101,55,5,0,0,115,34,0, - 0,0,0,2,10,1,10,1,4,1,4,1,8,1,8,1, - 12,2,10,1,4,1,14,1,2,1,8,1,8,1,8,1, - 12,1,14,2,114,23,1,0,0,99,0,0,0,0,0,0, - 0,0,3,0,0,0,3,0,0,0,67,0,0,0,115,38, - 0,0,0,116,0,116,1,106,2,131,0,102,2,125,0,116, - 3,116,4,102,2,125,1,116,5,116,6,102,2,125,2,124, - 0,124,1,124,2,103,3,83,0,41,1,122,95,82,101,116, - 117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,102, - 105,108,101,45,98,97,115,101,100,32,109,111,100,117,108,101, - 32,108,111,97,100,101,114,115,46,10,10,32,32,32,32,69, - 97,99,104,32,105,116,101,109,32,105,115,32,97,32,116,117, - 112,108,101,32,40,108,111,97,100,101,114,44,32,115,117,102, - 102,105,120,101,115,41,46,10,32,32,32,32,41,7,114,221, - 0,0,0,114,143,0,0,0,218,18,101,120,116,101,110,115, - 105,111,110,95,115,117,102,102,105,120,101,115,114,215,0,0, - 0,114,88,0,0,0,114,220,0,0,0,114,78,0,0,0, - 41,3,90,10,101,120,116,101,110,115,105,111,110,115,90,6, - 115,111,117,114,99,101,90,8,98,121,116,101,99,111,100,101, + 114,248,0,0,0,30,4,0,0,115,22,0,0,0,8,2, + 4,2,12,8,12,13,12,22,12,15,2,1,12,31,2,1, + 12,23,2,1,114,248,0,0,0,99,0,0,0,0,0,0, + 0,0,0,0,0,0,3,0,0,0,64,0,0,0,115,90, + 0,0,0,101,0,90,1,100,0,90,2,100,1,90,3,100, + 2,100,3,132,0,90,4,100,4,100,5,132,0,90,5,101, + 6,90,7,100,6,100,7,132,0,90,8,100,8,100,9,132, + 0,90,9,100,19,100,11,100,12,132,1,90,10,100,13,100, + 14,132,0,90,11,101,12,100,15,100,16,132,0,131,1,90, + 13,100,17,100,18,132,0,90,14,100,10,83,0,41,20,218, + 10,70,105,108,101,70,105,110,100,101,114,122,172,70,105,108, + 101,45,98,97,115,101,100,32,102,105,110,100,101,114,46,10, + 10,32,32,32,32,73,110,116,101,114,97,99,116,105,111,110, + 115,32,119,105,116,104,32,116,104,101,32,102,105,108,101,32, + 115,121,115,116,101,109,32,97,114,101,32,99,97,99,104,101, + 100,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99, + 101,44,32,98,101,105,110,103,10,32,32,32,32,114,101,102, + 114,101,115,104,101,100,32,119,104,101,110,32,116,104,101,32, + 100,105,114,101,99,116,111,114,121,32,116,104,101,32,102,105, + 110,100,101,114,32,105,115,32,104,97,110,100,108,105,110,103, + 32,104,97,115,32,98,101,101,110,32,109,111,100,105,102,105, + 101,100,46,10,10,32,32,32,32,99,2,0,0,0,0,0, + 0,0,5,0,0,0,5,0,0,0,7,0,0,0,115,88, + 0,0,0,103,0,125,3,120,40,124,2,68,0,93,32,92, + 2,137,0,125,4,124,3,106,0,135,0,102,1,100,1,100, + 2,132,8,124,4,68,0,131,1,131,1,1,0,113,10,87, + 0,124,3,124,0,95,1,124,1,112,58,100,3,124,0,95, + 2,100,6,124,0,95,3,116,4,131,0,124,0,95,5,116, + 4,131,0,124,0,95,6,100,5,83,0,41,7,122,154,73, + 110,105,116,105,97,108,105,122,101,32,119,105,116,104,32,116, + 104,101,32,112,97,116,104,32,116,111,32,115,101,97,114,99, + 104,32,111,110,32,97,110,100,32,97,32,118,97,114,105,97, + 98,108,101,32,110,117,109,98,101,114,32,111,102,10,32,32, + 32,32,32,32,32,32,50,45,116,117,112,108,101,115,32,99, + 111,110,116,97,105,110,105,110,103,32,116,104,101,32,108,111, + 97,100,101,114,32,97,110,100,32,116,104,101,32,102,105,108, + 101,32,115,117,102,102,105,120,101,115,32,116,104,101,32,108, + 111,97,100,101,114,10,32,32,32,32,32,32,32,32,114,101, + 99,111,103,110,105,122,101,115,46,99,1,0,0,0,0,0, + 0,0,2,0,0,0,3,0,0,0,51,0,0,0,115,22, + 0,0,0,124,0,93,14,125,1,124,1,136,0,102,2,86, + 0,1,0,113,2,100,0,83,0,41,1,78,114,4,0,0, + 0,41,2,114,24,0,0,0,114,222,0,0,0,41,1,114, + 124,0,0,0,114,4,0,0,0,114,6,0,0,0,114,224, + 0,0,0,177,4,0,0,115,2,0,0,0,4,0,122,38, + 70,105,108,101,70,105,110,100,101,114,46,95,95,105,110,105, + 116,95,95,46,60,108,111,99,97,108,115,62,46,60,103,101, + 110,101,120,112,114,62,114,61,0,0,0,114,31,0,0,0, + 78,114,91,0,0,0,41,7,114,147,0,0,0,218,8,95, + 108,111,97,100,101,114,115,114,37,0,0,0,218,11,95,112, + 97,116,104,95,109,116,105,109,101,218,3,115,101,116,218,11, + 95,112,97,116,104,95,99,97,99,104,101,218,19,95,114,101, + 108,97,120,101,100,95,112,97,116,104,95,99,97,99,104,101, + 41,5,114,104,0,0,0,114,37,0,0,0,218,14,108,111, + 97,100,101,114,95,100,101,116,97,105,108,115,90,7,108,111, + 97,100,101,114,115,114,164,0,0,0,114,4,0,0,0,41, + 1,114,124,0,0,0,114,6,0,0,0,114,182,0,0,0, + 171,4,0,0,115,16,0,0,0,0,4,4,1,14,1,28, + 1,6,2,10,1,6,1,8,1,122,19,70,105,108,101,70, + 105,110,100,101,114,46,95,95,105,110,105,116,95,95,99,1, + 0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,67, + 0,0,0,115,10,0,0,0,100,3,124,0,95,0,100,2, + 83,0,41,4,122,31,73,110,118,97,108,105,100,97,116,101, + 32,116,104,101,32,100,105,114,101,99,116,111,114,121,32,109, + 116,105,109,101,46,114,31,0,0,0,78,114,91,0,0,0, + 41,1,114,7,1,0,0,41,1,114,104,0,0,0,114,4, + 0,0,0,114,4,0,0,0,114,6,0,0,0,114,249,0, + 0,0,185,4,0,0,115,2,0,0,0,0,2,122,28,70, + 105,108,101,70,105,110,100,101,114,46,105,110,118,97,108,105, + 100,97,116,101,95,99,97,99,104,101,115,99,2,0,0,0, + 0,0,0,0,3,0,0,0,2,0,0,0,67,0,0,0, + 115,42,0,0,0,124,0,106,0,124,1,131,1,125,2,124, + 2,100,1,107,8,114,26,100,1,103,0,102,2,83,0,124, + 2,106,1,124,2,106,2,112,38,103,0,102,2,83,0,41, + 2,122,197,84,114,121,32,116,111,32,102,105,110,100,32,97, + 32,108,111,97,100,101,114,32,102,111,114,32,116,104,101,32, + 115,112,101,99,105,102,105,101,100,32,109,111,100,117,108,101, + 44,32,111,114,32,116,104,101,32,110,97,109,101,115,112,97, + 99,101,10,32,32,32,32,32,32,32,32,112,97,99,107,97, + 103,101,32,112,111,114,116,105,111,110,115,46,32,82,101,116, + 117,114,110,115,32,40,108,111,97,100,101,114,44,32,108,105, + 115,116,45,111,102,45,112,111,114,116,105,111,110,115,41,46, + 10,10,32,32,32,32,32,32,32,32,84,104,105,115,32,109, + 101,116,104,111,100,32,105,115,32,100,101,112,114,101,99,97, + 116,101,100,46,32,32,85,115,101,32,102,105,110,100,95,115, + 112,101,99,40,41,32,105,110,115,116,101,97,100,46,10,10, + 32,32,32,32,32,32,32,32,78,41,3,114,178,0,0,0, + 114,124,0,0,0,114,154,0,0,0,41,3,114,104,0,0, + 0,114,123,0,0,0,114,162,0,0,0,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,121,0,0,0,191, + 4,0,0,115,8,0,0,0,0,7,10,1,8,1,8,1, + 122,22,70,105,108,101,70,105,110,100,101,114,46,102,105,110, + 100,95,108,111,97,100,101,114,99,6,0,0,0,0,0,0, + 0,7,0,0,0,6,0,0,0,67,0,0,0,115,26,0, + 0,0,124,1,124,2,124,3,131,2,125,6,116,0,124,2, + 124,3,124,6,124,4,100,1,141,4,83,0,41,2,78,41, + 2,114,124,0,0,0,114,154,0,0,0,41,1,114,165,0, + 0,0,41,7,114,104,0,0,0,114,163,0,0,0,114,123, + 0,0,0,114,37,0,0,0,90,4,115,109,115,108,114,177, + 0,0,0,114,124,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,4,1,0,0,203,4,0,0, + 115,6,0,0,0,0,1,10,1,8,1,122,20,70,105,108, + 101,70,105,110,100,101,114,46,95,103,101,116,95,115,112,101, + 99,78,99,3,0,0,0,0,0,0,0,14,0,0,0,15, + 0,0,0,67,0,0,0,115,98,1,0,0,100,1,125,3, + 124,1,106,0,100,2,131,1,100,3,25,0,125,4,121,24, + 116,1,124,0,106,2,112,34,116,3,106,4,131,0,131,1, + 106,5,125,5,87,0,110,24,4,0,116,6,107,10,114,66, + 1,0,1,0,1,0,100,10,125,5,89,0,110,2,88,0, + 124,5,124,0,106,7,107,3,114,92,124,0,106,8,131,0, + 1,0,124,5,124,0,95,7,116,9,131,0,114,114,124,0, + 106,10,125,6,124,4,106,11,131,0,125,7,110,10,124,0, + 106,12,125,6,124,4,125,7,124,7,124,6,107,6,114,218, + 116,13,124,0,106,2,124,4,131,2,125,8,120,72,124,0, + 106,14,68,0,93,54,92,2,125,9,125,10,100,5,124,9, + 23,0,125,11,116,13,124,8,124,11,131,2,125,12,116,15, + 124,12,131,1,114,152,124,0,106,16,124,10,124,1,124,12, + 124,8,103,1,124,2,131,5,83,0,113,152,87,0,116,17, + 124,8,131,1,125,3,120,88,124,0,106,14,68,0,93,78, + 92,2,125,9,125,10,116,13,124,0,106,2,124,4,124,9, + 23,0,131,2,125,12,116,18,106,19,100,6,124,12,100,3, + 100,7,141,3,1,0,124,7,124,9,23,0,124,6,107,6, + 114,226,116,15,124,12,131,1,114,226,124,0,106,16,124,10, + 124,1,124,12,100,8,124,2,131,5,83,0,113,226,87,0, + 124,3,144,1,114,94,116,18,106,19,100,9,124,8,131,2, + 1,0,116,18,106,20,124,1,100,8,131,2,125,13,124,8, + 103,1,124,13,95,21,124,13,83,0,100,8,83,0,41,11, + 122,111,84,114,121,32,116,111,32,102,105,110,100,32,97,32, + 115,112,101,99,32,102,111,114,32,116,104,101,32,115,112,101, + 99,105,102,105,101,100,32,109,111,100,117,108,101,46,10,10, + 32,32,32,32,32,32,32,32,82,101,116,117,114,110,115,32, + 116,104,101,32,109,97,116,99,104,105,110,103,32,115,112,101, + 99,44,32,111,114,32,78,111,110,101,32,105,102,32,110,111, + 116,32,102,111,117,110,100,46,10,32,32,32,32,32,32,32, + 32,70,114,61,0,0,0,114,59,0,0,0,114,31,0,0, + 0,114,182,0,0,0,122,9,116,114,121,105,110,103,32,123, + 125,41,1,90,9,118,101,114,98,111,115,105,116,121,78,122, + 25,112,111,115,115,105,98,108,101,32,110,97,109,101,115,112, + 97,99,101,32,102,111,114,32,123,125,114,91,0,0,0,41, + 22,114,34,0,0,0,114,41,0,0,0,114,37,0,0,0, + 114,3,0,0,0,114,47,0,0,0,114,216,0,0,0,114, + 42,0,0,0,114,7,1,0,0,218,11,95,102,105,108,108, + 95,99,97,99,104,101,114,7,0,0,0,114,10,1,0,0, + 114,92,0,0,0,114,9,1,0,0,114,30,0,0,0,114, + 6,1,0,0,114,46,0,0,0,114,4,1,0,0,114,48, + 0,0,0,114,118,0,0,0,114,133,0,0,0,114,158,0, + 0,0,114,154,0,0,0,41,14,114,104,0,0,0,114,123, + 0,0,0,114,177,0,0,0,90,12,105,115,95,110,97,109, + 101,115,112,97,99,101,90,11,116,97,105,108,95,109,111,100, + 117,108,101,114,130,0,0,0,90,5,99,97,99,104,101,90, + 12,99,97,99,104,101,95,109,111,100,117,108,101,90,9,98, + 97,115,101,95,112,97,116,104,114,222,0,0,0,114,163,0, + 0,0,90,13,105,110,105,116,95,102,105,108,101,110,97,109, + 101,90,9,102,117,108,108,95,112,97,116,104,114,162,0,0, + 0,114,4,0,0,0,114,4,0,0,0,114,6,0,0,0, + 114,178,0,0,0,208,4,0,0,115,70,0,0,0,0,5, + 4,1,14,1,2,1,24,1,14,1,10,1,10,1,8,1, + 6,2,6,1,6,1,10,2,6,1,4,2,8,1,12,1, + 16,1,8,1,10,1,8,1,24,4,8,2,16,1,16,1, + 16,1,12,1,8,1,10,1,12,1,6,1,12,1,12,1, + 8,1,4,1,122,20,70,105,108,101,70,105,110,100,101,114, + 46,102,105,110,100,95,115,112,101,99,99,1,0,0,0,0, + 0,0,0,9,0,0,0,13,0,0,0,67,0,0,0,115, + 194,0,0,0,124,0,106,0,125,1,121,22,116,1,106,2, + 124,1,112,22,116,1,106,3,131,0,131,1,125,2,87,0, + 110,30,4,0,116,4,116,5,116,6,102,3,107,10,114,58, + 1,0,1,0,1,0,103,0,125,2,89,0,110,2,88,0, + 116,7,106,8,106,9,100,1,131,1,115,84,116,10,124,2, + 131,1,124,0,95,11,110,78,116,10,131,0,125,3,120,64, + 124,2,68,0,93,56,125,4,124,4,106,12,100,2,131,1, + 92,3,125,5,125,6,125,7,124,6,114,138,100,3,106,13, + 124,5,124,7,106,14,131,0,131,2,125,8,110,4,124,5, + 125,8,124,3,106,15,124,8,131,1,1,0,113,96,87,0, + 124,3,124,0,95,11,116,7,106,8,106,9,116,16,131,1, + 114,190,100,4,100,5,132,0,124,2,68,0,131,1,124,0, + 95,17,100,6,83,0,41,7,122,68,70,105,108,108,32,116, + 104,101,32,99,97,99,104,101,32,111,102,32,112,111,116,101, + 110,116,105,97,108,32,109,111,100,117,108,101,115,32,97,110, + 100,32,112,97,99,107,97,103,101,115,32,102,111,114,32,116, + 104,105,115,32,100,105,114,101,99,116,111,114,121,46,114,0, + 0,0,0,114,61,0,0,0,122,5,123,125,46,123,125,99, + 1,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0, + 83,0,0,0,115,20,0,0,0,104,0,124,0,93,12,125, + 1,124,1,106,0,131,0,146,2,113,4,83,0,114,4,0, + 0,0,41,1,114,92,0,0,0,41,2,114,24,0,0,0, + 90,2,102,110,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,250,9,60,115,101,116,99,111,109,112,62,29,5, + 0,0,115,2,0,0,0,6,0,122,41,70,105,108,101,70, + 105,110,100,101,114,46,95,102,105,108,108,95,99,97,99,104, + 101,46,60,108,111,99,97,108,115,62,46,60,115,101,116,99, + 111,109,112,62,78,41,18,114,37,0,0,0,114,3,0,0, + 0,90,7,108,105,115,116,100,105,114,114,47,0,0,0,114, + 255,0,0,0,218,15,80,101,114,109,105,115,115,105,111,110, + 69,114,114,111,114,218,18,78,111,116,65,68,105,114,101,99, + 116,111,114,121,69,114,114,111,114,114,8,0,0,0,114,9, + 0,0,0,114,10,0,0,0,114,8,1,0,0,114,9,1, + 0,0,114,87,0,0,0,114,50,0,0,0,114,92,0,0, + 0,218,3,97,100,100,114,11,0,0,0,114,10,1,0,0, + 41,9,114,104,0,0,0,114,37,0,0,0,90,8,99,111, + 110,116,101,110,116,115,90,21,108,111,119,101,114,95,115,117, + 102,102,105,120,95,99,111,110,116,101,110,116,115,114,244,0, + 0,0,114,102,0,0,0,114,234,0,0,0,114,222,0,0, + 0,90,8,110,101,119,95,110,97,109,101,114,4,0,0,0, + 114,4,0,0,0,114,6,0,0,0,114,12,1,0,0,0, + 5,0,0,115,34,0,0,0,0,2,6,1,2,1,22,1, + 20,3,10,3,12,1,12,7,6,1,10,1,16,1,4,1, + 18,2,4,1,14,1,6,1,12,1,122,22,70,105,108,101, + 70,105,110,100,101,114,46,95,102,105,108,108,95,99,97,99, + 104,101,99,1,0,0,0,0,0,0,0,3,0,0,0,3, + 0,0,0,7,0,0,0,115,18,0,0,0,135,0,135,1, + 102,2,100,1,100,2,132,8,125,2,124,2,83,0,41,3, + 97,20,1,0,0,65,32,99,108,97,115,115,32,109,101,116, + 104,111,100,32,119,104,105,99,104,32,114,101,116,117,114,110, + 115,32,97,32,99,108,111,115,117,114,101,32,116,111,32,117, + 115,101,32,111,110,32,115,121,115,46,112,97,116,104,95,104, + 111,111,107,10,32,32,32,32,32,32,32,32,119,104,105,99, + 104,32,119,105,108,108,32,114,101,116,117,114,110,32,97,110, + 32,105,110,115,116,97,110,99,101,32,117,115,105,110,103,32, + 116,104,101,32,115,112,101,99,105,102,105,101,100,32,108,111, + 97,100,101,114,115,32,97,110,100,32,116,104,101,32,112,97, + 116,104,10,32,32,32,32,32,32,32,32,99,97,108,108,101, + 100,32,111,110,32,116,104,101,32,99,108,111,115,117,114,101, + 46,10,10,32,32,32,32,32,32,32,32,73,102,32,116,104, + 101,32,112,97,116,104,32,99,97,108,108,101,100,32,111,110, + 32,116,104,101,32,99,108,111,115,117,114,101,32,105,115,32, + 110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,44, + 32,73,109,112,111,114,116,69,114,114,111,114,32,105,115,10, + 32,32,32,32,32,32,32,32,114,97,105,115,101,100,46,10, + 10,32,32,32,32,32,32,32,32,99,1,0,0,0,0,0, + 0,0,1,0,0,0,4,0,0,0,19,0,0,0,115,34, + 0,0,0,116,0,124,0,131,1,115,20,116,1,100,1,124, + 0,100,2,141,2,130,1,136,0,124,0,102,1,136,1,158, + 2,142,0,83,0,41,3,122,45,80,97,116,104,32,104,111, + 111,107,32,102,111,114,32,105,109,112,111,114,116,108,105,98, + 46,109,97,99,104,105,110,101,114,121,46,70,105,108,101,70, + 105,110,100,101,114,46,122,30,111,110,108,121,32,100,105,114, + 101,99,116,111,114,105,101,115,32,97,114,101,32,115,117,112, + 112,111,114,116,101,100,41,1,114,37,0,0,0,41,2,114, + 48,0,0,0,114,103,0,0,0,41,1,114,37,0,0,0, + 41,2,114,168,0,0,0,114,11,1,0,0,114,4,0,0, + 0,114,6,0,0,0,218,24,112,97,116,104,95,104,111,111, + 107,95,102,111,114,95,70,105,108,101,70,105,110,100,101,114, + 41,5,0,0,115,6,0,0,0,0,2,8,1,12,1,122, + 54,70,105,108,101,70,105,110,100,101,114,46,112,97,116,104, + 95,104,111,111,107,46,60,108,111,99,97,108,115,62,46,112, + 97,116,104,95,104,111,111,107,95,102,111,114,95,70,105,108, + 101,70,105,110,100,101,114,114,4,0,0,0,41,3,114,168, + 0,0,0,114,11,1,0,0,114,17,1,0,0,114,4,0, + 0,0,41,2,114,168,0,0,0,114,11,1,0,0,114,6, + 0,0,0,218,9,112,97,116,104,95,104,111,111,107,31,5, + 0,0,115,4,0,0,0,0,10,14,6,122,20,70,105,108, + 101,70,105,110,100,101,114,46,112,97,116,104,95,104,111,111, + 107,99,1,0,0,0,0,0,0,0,1,0,0,0,2,0, + 0,0,67,0,0,0,115,12,0,0,0,100,1,106,0,124, + 0,106,1,131,1,83,0,41,2,78,122,16,70,105,108,101, + 70,105,110,100,101,114,40,123,33,114,125,41,41,2,114,50, + 0,0,0,114,37,0,0,0,41,1,114,104,0,0,0,114, + 4,0,0,0,114,4,0,0,0,114,6,0,0,0,114,243, + 0,0,0,49,5,0,0,115,2,0,0,0,0,1,122,19, + 70,105,108,101,70,105,110,100,101,114,46,95,95,114,101,112, + 114,95,95,41,1,78,41,15,114,109,0,0,0,114,108,0, + 0,0,114,110,0,0,0,114,111,0,0,0,114,182,0,0, + 0,114,249,0,0,0,114,127,0,0,0,114,179,0,0,0, + 114,121,0,0,0,114,4,1,0,0,114,178,0,0,0,114, + 12,1,0,0,114,180,0,0,0,114,18,1,0,0,114,243, + 0,0,0,114,4,0,0,0,114,4,0,0,0,114,4,0, + 0,0,114,6,0,0,0,114,5,1,0,0,162,4,0,0, + 115,20,0,0,0,8,7,4,2,8,14,8,4,4,2,8, + 12,8,5,10,48,8,31,12,18,114,5,1,0,0,99,4, + 0,0,0,0,0,0,0,6,0,0,0,11,0,0,0,67, + 0,0,0,115,146,0,0,0,124,0,106,0,100,1,131,1, + 125,4,124,0,106,0,100,2,131,1,125,5,124,4,115,66, + 124,5,114,36,124,5,106,1,125,4,110,30,124,2,124,3, + 107,2,114,56,116,2,124,1,124,2,131,2,125,4,110,10, + 116,3,124,1,124,2,131,2,125,4,124,5,115,84,116,4, + 124,1,124,2,124,4,100,3,141,3,125,5,121,36,124,5, + 124,0,100,2,60,0,124,4,124,0,100,1,60,0,124,2, + 124,0,100,4,60,0,124,3,124,0,100,5,60,0,87,0, + 110,20,4,0,116,5,107,10,114,140,1,0,1,0,1,0, + 89,0,110,2,88,0,100,0,83,0,41,6,78,218,10,95, + 95,108,111,97,100,101,114,95,95,218,8,95,95,115,112,101, + 99,95,95,41,1,114,124,0,0,0,90,8,95,95,102,105, + 108,101,95,95,90,10,95,95,99,97,99,104,101,100,95,95, + 41,6,218,3,103,101,116,114,124,0,0,0,114,220,0,0, + 0,114,215,0,0,0,114,165,0,0,0,218,9,69,120,99, + 101,112,116,105,111,110,41,6,90,2,110,115,114,102,0,0, + 0,90,8,112,97,116,104,110,97,109,101,90,9,99,112,97, + 116,104,110,97,109,101,114,124,0,0,0,114,162,0,0,0, + 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,218, + 14,95,102,105,120,95,117,112,95,109,111,100,117,108,101,55, + 5,0,0,115,34,0,0,0,0,2,10,1,10,1,4,1, + 4,1,8,1,8,1,12,2,10,1,4,1,14,1,2,1, + 8,1,8,1,8,1,12,1,14,2,114,23,1,0,0,99, + 0,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0, + 67,0,0,0,115,38,0,0,0,116,0,116,1,106,2,131, + 0,102,2,125,0,116,3,116,4,102,2,125,1,116,5,116, + 6,102,2,125,2,124,0,124,1,124,2,103,3,83,0,41, + 1,122,95,82,101,116,117,114,110,115,32,97,32,108,105,115, + 116,32,111,102,32,102,105,108,101,45,98,97,115,101,100,32, + 109,111,100,117,108,101,32,108,111,97,100,101,114,115,46,10, + 10,32,32,32,32,69,97,99,104,32,105,116,101,109,32,105, + 115,32,97,32,116,117,112,108,101,32,40,108,111,97,100,101, + 114,44,32,115,117,102,102,105,120,101,115,41,46,10,32,32, + 32,32,41,7,114,221,0,0,0,114,143,0,0,0,218,18, + 101,120,116,101,110,115,105,111,110,95,115,117,102,102,105,120, + 101,115,114,215,0,0,0,114,88,0,0,0,114,220,0,0, + 0,114,78,0,0,0,41,3,90,10,101,120,116,101,110,115, + 105,111,110,115,90,6,115,111,117,114,99,101,90,8,98,121, + 116,101,99,111,100,101,114,4,0,0,0,114,4,0,0,0, + 114,6,0,0,0,114,159,0,0,0,78,5,0,0,115,8, + 0,0,0,0,5,12,1,8,1,8,1,114,159,0,0,0, + 99,1,0,0,0,0,0,0,0,12,0,0,0,12,0,0, + 0,67,0,0,0,115,188,1,0,0,124,0,97,0,116,0, + 106,1,97,1,116,0,106,2,97,2,116,1,106,3,116,4, + 25,0,125,1,120,56,100,26,68,0,93,48,125,2,124,2, + 116,1,106,3,107,7,114,58,116,0,106,5,124,2,131,1, + 125,3,110,10,116,1,106,3,124,2,25,0,125,3,116,6, + 124,1,124,2,124,3,131,3,1,0,113,32,87,0,100,5, + 100,6,103,1,102,2,100,7,100,8,100,6,103,2,102,2, + 102,2,125,4,120,118,124,4,68,0,93,102,92,2,125,5, + 125,6,116,7,100,9,100,10,132,0,124,6,68,0,131,1, + 131,1,115,142,116,8,130,1,124,6,100,11,25,0,125,7, + 124,5,116,1,106,3,107,6,114,174,116,1,106,3,124,5, + 25,0,125,8,80,0,113,112,121,16,116,0,106,5,124,5, + 131,1,125,8,80,0,87,0,113,112,4,0,116,9,107,10, + 114,212,1,0,1,0,1,0,119,112,89,0,113,112,88,0, + 113,112,87,0,116,9,100,12,131,1,130,1,116,6,124,1, + 100,13,124,8,131,3,1,0,116,6,124,1,100,14,124,7, + 131,3,1,0,116,6,124,1,100,15,100,16,106,10,124,6, + 131,1,131,3,1,0,121,14,116,0,106,5,100,17,131,1, + 125,9,87,0,110,26,4,0,116,9,107,10,144,1,114,52, + 1,0,1,0,1,0,100,18,125,9,89,0,110,2,88,0, + 116,6,124,1,100,17,124,9,131,3,1,0,116,0,106,5, + 100,19,131,1,125,10,116,6,124,1,100,19,124,10,131,3, + 1,0,124,5,100,7,107,2,144,1,114,120,116,0,106,5, + 100,20,131,1,125,11,116,6,124,1,100,21,124,11,131,3, + 1,0,116,6,124,1,100,22,116,11,131,0,131,3,1,0, + 116,12,106,13,116,2,106,14,131,0,131,1,1,0,124,5, + 100,7,107,2,144,1,114,184,116,15,106,16,100,23,131,1, + 1,0,100,24,116,12,107,6,144,1,114,184,100,25,116,17, + 95,18,100,18,83,0,41,27,122,205,83,101,116,117,112,32, + 116,104,101,32,112,97,116,104,45,98,97,115,101,100,32,105, + 109,112,111,114,116,101,114,115,32,102,111,114,32,105,109,112, + 111,114,116,108,105,98,32,98,121,32,105,109,112,111,114,116, + 105,110,103,32,110,101,101,100,101,100,10,32,32,32,32,98, + 117,105,108,116,45,105,110,32,109,111,100,117,108,101,115,32, + 97,110,100,32,105,110,106,101,99,116,105,110,103,32,116,104, + 101,109,32,105,110,116,111,32,116,104,101,32,103,108,111,98, + 97,108,32,110,97,109,101,115,112,97,99,101,46,10,10,32, + 32,32,32,79,116,104,101,114,32,99,111,109,112,111,110,101, + 110,116,115,32,97,114,101,32,101,120,116,114,97,99,116,101, + 100,32,102,114,111,109,32,116,104,101,32,99,111,114,101,32, + 98,111,111,116,115,116,114,97,112,32,109,111,100,117,108,101, + 46,10,10,32,32,32,32,114,52,0,0,0,114,63,0,0, + 0,218,8,98,117,105,108,116,105,110,115,114,140,0,0,0, + 90,5,112,111,115,105,120,250,1,47,218,2,110,116,250,1, + 92,99,1,0,0,0,0,0,0,0,2,0,0,0,3,0, + 0,0,115,0,0,0,115,26,0,0,0,124,0,93,18,125, + 1,116,0,124,1,131,1,100,0,107,2,86,0,1,0,113, + 2,100,1,83,0,41,2,114,31,0,0,0,78,41,1,114, + 33,0,0,0,41,2,114,24,0,0,0,114,81,0,0,0, 114,4,0,0,0,114,4,0,0,0,114,6,0,0,0,114, - 159,0,0,0,78,5,0,0,115,8,0,0,0,0,5,12, - 1,8,1,8,1,114,159,0,0,0,99,1,0,0,0,0, - 0,0,0,12,0,0,0,12,0,0,0,67,0,0,0,115, - 188,1,0,0,124,0,97,0,116,0,106,1,97,1,116,0, - 106,2,97,2,116,1,106,3,116,4,25,0,125,1,120,56, - 100,26,68,0,93,48,125,2,124,2,116,1,106,3,107,7, - 114,58,116,0,106,5,124,2,131,1,125,3,110,10,116,1, - 106,3,124,2,25,0,125,3,116,6,124,1,124,2,124,3, - 131,3,1,0,113,32,87,0,100,5,100,6,103,1,102,2, - 100,7,100,8,100,6,103,2,102,2,102,2,125,4,120,118, - 124,4,68,0,93,102,92,2,125,5,125,6,116,7,100,9, - 100,10,132,0,124,6,68,0,131,1,131,1,115,142,116,8, - 130,1,124,6,100,11,25,0,125,7,124,5,116,1,106,3, - 107,6,114,174,116,1,106,3,124,5,25,0,125,8,80,0, - 113,112,121,16,116,0,106,5,124,5,131,1,125,8,80,0, - 87,0,113,112,4,0,116,9,107,10,114,212,1,0,1,0, - 1,0,119,112,89,0,113,112,88,0,113,112,87,0,116,9, - 100,12,131,1,130,1,116,6,124,1,100,13,124,8,131,3, - 1,0,116,6,124,1,100,14,124,7,131,3,1,0,116,6, - 124,1,100,15,100,16,106,10,124,6,131,1,131,3,1,0, - 121,14,116,0,106,5,100,17,131,1,125,9,87,0,110,26, - 4,0,116,9,107,10,144,1,114,52,1,0,1,0,1,0, - 100,18,125,9,89,0,110,2,88,0,116,6,124,1,100,17, - 124,9,131,3,1,0,116,0,106,5,100,19,131,1,125,10, - 116,6,124,1,100,19,124,10,131,3,1,0,124,5,100,7, - 107,2,144,1,114,120,116,0,106,5,100,20,131,1,125,11, - 116,6,124,1,100,21,124,11,131,3,1,0,116,6,124,1, - 100,22,116,11,131,0,131,3,1,0,116,12,106,13,116,2, - 106,14,131,0,131,1,1,0,124,5,100,7,107,2,144,1, - 114,184,116,15,106,16,100,23,131,1,1,0,100,24,116,12, - 107,6,144,1,114,184,100,25,116,17,95,18,100,18,83,0, - 41,27,122,205,83,101,116,117,112,32,116,104,101,32,112,97, - 116,104,45,98,97,115,101,100,32,105,109,112,111,114,116,101, - 114,115,32,102,111,114,32,105,109,112,111,114,116,108,105,98, - 32,98,121,32,105,109,112,111,114,116,105,110,103,32,110,101, - 101,100,101,100,10,32,32,32,32,98,117,105,108,116,45,105, - 110,32,109,111,100,117,108,101,115,32,97,110,100,32,105,110, - 106,101,99,116,105,110,103,32,116,104,101,109,32,105,110,116, - 111,32,116,104,101,32,103,108,111,98,97,108,32,110,97,109, - 101,115,112,97,99,101,46,10,10,32,32,32,32,79,116,104, - 101,114,32,99,111,109,112,111,110,101,110,116,115,32,97,114, - 101,32,101,120,116,114,97,99,116,101,100,32,102,114,111,109, - 32,116,104,101,32,99,111,114,101,32,98,111,111,116,115,116, - 114,97,112,32,109,111,100,117,108,101,46,10,10,32,32,32, - 32,114,52,0,0,0,114,63,0,0,0,218,8,98,117,105, - 108,116,105,110,115,114,140,0,0,0,90,5,112,111,115,105, - 120,250,1,47,218,2,110,116,250,1,92,99,1,0,0,0, - 0,0,0,0,2,0,0,0,3,0,0,0,115,0,0,0, - 115,26,0,0,0,124,0,93,18,125,1,116,0,124,1,131, - 1,100,0,107,2,86,0,1,0,113,2,100,1,83,0,41, - 2,114,31,0,0,0,78,41,1,114,33,0,0,0,41,2, - 114,24,0,0,0,114,81,0,0,0,114,4,0,0,0,114, - 4,0,0,0,114,6,0,0,0,114,224,0,0,0,114,5, - 0,0,115,2,0,0,0,4,0,122,25,95,115,101,116,117, - 112,46,60,108,111,99,97,108,115,62,46,60,103,101,110,101, - 120,112,114,62,114,62,0,0,0,122,30,105,109,112,111,114, - 116,108,105,98,32,114,101,113,117,105,114,101,115,32,112,111, - 115,105,120,32,111,114,32,110,116,114,3,0,0,0,114,27, - 0,0,0,114,23,0,0,0,114,32,0,0,0,90,7,95, - 116,104,114,101,97,100,78,90,8,95,119,101,97,107,114,101, - 102,90,6,119,105,110,114,101,103,114,167,0,0,0,114,7, - 0,0,0,122,4,46,112,121,119,122,6,95,100,46,112,121, - 100,84,41,4,114,52,0,0,0,114,63,0,0,0,114,25, - 1,0,0,114,140,0,0,0,41,19,114,118,0,0,0,114, - 8,0,0,0,114,143,0,0,0,114,236,0,0,0,114,109, - 0,0,0,90,18,95,98,117,105,108,116,105,110,95,102,114, - 111,109,95,110,97,109,101,114,113,0,0,0,218,3,97,108, - 108,218,14,65,115,115,101,114,116,105,111,110,69,114,114,111, - 114,114,103,0,0,0,114,28,0,0,0,114,13,0,0,0, - 114,226,0,0,0,114,147,0,0,0,114,24,1,0,0,114, - 88,0,0,0,114,161,0,0,0,114,166,0,0,0,114,170, - 0,0,0,41,12,218,17,95,98,111,111,116,115,116,114,97, - 112,95,109,111,100,117,108,101,90,11,115,101,108,102,95,109, - 111,100,117,108,101,90,12,98,117,105,108,116,105,110,95,110, - 97,109,101,90,14,98,117,105,108,116,105,110,95,109,111,100, - 117,108,101,90,10,111,115,95,100,101,116,97,105,108,115,90, - 10,98,117,105,108,116,105,110,95,111,115,114,23,0,0,0, - 114,27,0,0,0,90,9,111,115,95,109,111,100,117,108,101, - 90,13,116,104,114,101,97,100,95,109,111,100,117,108,101,90, - 14,119,101,97,107,114,101,102,95,109,111,100,117,108,101,90, - 13,119,105,110,114,101,103,95,109,111,100,117,108,101,114,4, - 0,0,0,114,4,0,0,0,114,6,0,0,0,218,6,95, - 115,101,116,117,112,89,5,0,0,115,82,0,0,0,0,8, - 4,1,6,1,6,3,10,1,10,1,10,1,12,2,10,1, - 16,3,22,1,14,2,22,1,8,1,10,1,10,1,4,2, - 2,1,10,1,6,1,14,1,12,2,8,1,12,1,12,1, - 18,3,2,1,14,1,16,2,10,1,12,3,10,1,12,3, - 10,1,10,1,12,3,14,1,14,1,10,1,10,1,10,1, - 114,32,1,0,0,99,1,0,0,0,0,0,0,0,2,0, - 0,0,3,0,0,0,67,0,0,0,115,72,0,0,0,116, - 0,124,0,131,1,1,0,116,1,131,0,125,1,116,2,106, - 3,106,4,116,5,106,6,124,1,142,0,103,1,131,1,1, - 0,116,7,106,8,100,1,107,2,114,56,116,2,106,9,106, - 10,116,11,131,1,1,0,116,2,106,9,106,10,116,12,131, - 1,1,0,100,2,83,0,41,3,122,41,73,110,115,116,97, - 108,108,32,116,104,101,32,112,97,116,104,45,98,97,115,101, - 100,32,105,109,112,111,114,116,32,99,111,109,112,111,110,101, - 110,116,115,46,114,27,1,0,0,78,41,13,114,32,1,0, - 0,114,159,0,0,0,114,8,0,0,0,114,253,0,0,0, - 114,147,0,0,0,114,5,1,0,0,114,18,1,0,0,114, - 3,0,0,0,114,109,0,0,0,218,9,109,101,116,97,95, - 112,97,116,104,114,161,0,0,0,114,166,0,0,0,114,248, - 0,0,0,41,2,114,31,1,0,0,90,17,115,117,112,112, - 111,114,116,101,100,95,108,111,97,100,101,114,115,114,4,0, - 0,0,114,4,0,0,0,114,6,0,0,0,218,8,95,105, - 110,115,116,97,108,108,157,5,0,0,115,12,0,0,0,0, - 2,8,1,6,1,20,1,10,1,12,1,114,34,1,0,0, - 41,1,114,0,0,0,0,41,2,114,1,0,0,0,114,2, - 0,0,0,41,1,114,49,0,0,0,41,1,78,41,3,78, - 78,78,41,3,78,78,78,41,2,114,62,0,0,0,114,62, - 0,0,0,41,1,78,41,1,78,41,58,114,111,0,0,0, - 114,12,0,0,0,90,37,95,67,65,83,69,95,73,78,83, - 69,78,83,73,84,73,86,69,95,80,76,65,84,70,79,82, - 77,83,95,66,89,84,69,83,95,75,69,89,114,11,0,0, - 0,114,13,0,0,0,114,19,0,0,0,114,21,0,0,0, - 114,30,0,0,0,114,40,0,0,0,114,41,0,0,0,114, - 45,0,0,0,114,46,0,0,0,114,48,0,0,0,114,58, - 0,0,0,218,4,116,121,112,101,218,8,95,95,99,111,100, - 101,95,95,114,142,0,0,0,114,17,0,0,0,114,132,0, - 0,0,114,16,0,0,0,114,20,0,0,0,90,17,95,82, - 65,87,95,77,65,71,73,67,95,78,85,77,66,69,82,114, - 77,0,0,0,114,76,0,0,0,114,88,0,0,0,114,78, - 0,0,0,90,23,68,69,66,85,71,95,66,89,84,69,67, - 79,68,69,95,83,85,70,70,73,88,69,83,90,27,79,80, - 84,73,77,73,90,69,68,95,66,89,84,69,67,79,68,69, - 95,83,85,70,70,73,88,69,83,114,83,0,0,0,114,89, - 0,0,0,114,95,0,0,0,114,99,0,0,0,114,101,0, - 0,0,114,120,0,0,0,114,127,0,0,0,114,139,0,0, - 0,114,145,0,0,0,114,148,0,0,0,114,153,0,0,0, - 218,6,111,98,106,101,99,116,114,160,0,0,0,114,165,0, - 0,0,114,166,0,0,0,114,181,0,0,0,114,191,0,0, - 0,114,207,0,0,0,114,215,0,0,0,114,220,0,0,0, - 114,226,0,0,0,114,221,0,0,0,114,227,0,0,0,114, - 246,0,0,0,114,248,0,0,0,114,5,1,0,0,114,23, - 1,0,0,114,159,0,0,0,114,32,1,0,0,114,34,1, - 0,0,114,4,0,0,0,114,4,0,0,0,114,4,0,0, - 0,114,6,0,0,0,218,8,60,109,111,100,117,108,101,62, - 8,0,0,0,115,108,0,0,0,4,16,4,1,4,1,2, - 1,6,3,8,17,8,5,8,5,8,6,8,12,8,10,8, - 9,8,5,8,7,10,22,10,122,16,1,12,2,4,1,4, - 2,6,2,6,2,8,2,16,45,8,34,8,19,8,12,8, - 12,8,28,8,17,10,55,10,12,10,10,8,14,6,3,4, - 1,14,67,14,64,14,29,16,110,14,41,18,45,18,16,4, - 3,18,53,14,60,14,42,14,127,0,5,14,127,0,22,10, - 23,8,11,8,68, + 224,0,0,0,114,5,0,0,115,2,0,0,0,4,0,122, + 25,95,115,101,116,117,112,46,60,108,111,99,97,108,115,62, + 46,60,103,101,110,101,120,112,114,62,114,62,0,0,0,122, + 30,105,109,112,111,114,116,108,105,98,32,114,101,113,117,105, + 114,101,115,32,112,111,115,105,120,32,111,114,32,110,116,114, + 3,0,0,0,114,27,0,0,0,114,23,0,0,0,114,32, + 0,0,0,90,7,95,116,104,114,101,97,100,78,90,8,95, + 119,101,97,107,114,101,102,90,6,119,105,110,114,101,103,114, + 167,0,0,0,114,7,0,0,0,122,4,46,112,121,119,122, + 6,95,100,46,112,121,100,84,41,4,114,52,0,0,0,114, + 63,0,0,0,114,25,1,0,0,114,140,0,0,0,41,19, + 114,118,0,0,0,114,8,0,0,0,114,143,0,0,0,114, + 236,0,0,0,114,109,0,0,0,90,18,95,98,117,105,108, + 116,105,110,95,102,114,111,109,95,110,97,109,101,114,113,0, + 0,0,218,3,97,108,108,218,14,65,115,115,101,114,116,105, + 111,110,69,114,114,111,114,114,103,0,0,0,114,28,0,0, + 0,114,13,0,0,0,114,226,0,0,0,114,147,0,0,0, + 114,24,1,0,0,114,88,0,0,0,114,161,0,0,0,114, + 166,0,0,0,114,170,0,0,0,41,12,218,17,95,98,111, + 111,116,115,116,114,97,112,95,109,111,100,117,108,101,90,11, + 115,101,108,102,95,109,111,100,117,108,101,90,12,98,117,105, + 108,116,105,110,95,110,97,109,101,90,14,98,117,105,108,116, + 105,110,95,109,111,100,117,108,101,90,10,111,115,95,100,101, + 116,97,105,108,115,90,10,98,117,105,108,116,105,110,95,111, + 115,114,23,0,0,0,114,27,0,0,0,90,9,111,115,95, + 109,111,100,117,108,101,90,13,116,104,114,101,97,100,95,109, + 111,100,117,108,101,90,14,119,101,97,107,114,101,102,95,109, + 111,100,117,108,101,90,13,119,105,110,114,101,103,95,109,111, + 100,117,108,101,114,4,0,0,0,114,4,0,0,0,114,6, + 0,0,0,218,6,95,115,101,116,117,112,89,5,0,0,115, + 82,0,0,0,0,8,4,1,6,1,6,3,10,1,10,1, + 10,1,12,2,10,1,16,3,22,1,14,2,22,1,8,1, + 10,1,10,1,4,2,2,1,10,1,6,1,14,1,12,2, + 8,1,12,1,12,1,18,3,2,1,14,1,16,2,10,1, + 12,3,10,1,12,3,10,1,10,1,12,3,14,1,14,1, + 10,1,10,1,10,1,114,32,1,0,0,99,1,0,0,0, + 0,0,0,0,2,0,0,0,3,0,0,0,67,0,0,0, + 115,72,0,0,0,116,0,124,0,131,1,1,0,116,1,131, + 0,125,1,116,2,106,3,106,4,116,5,106,6,124,1,142, + 0,103,1,131,1,1,0,116,7,106,8,100,1,107,2,114, + 56,116,2,106,9,106,10,116,11,131,1,1,0,116,2,106, + 9,106,10,116,12,131,1,1,0,100,2,83,0,41,3,122, + 41,73,110,115,116,97,108,108,32,116,104,101,32,112,97,116, + 104,45,98,97,115,101,100,32,105,109,112,111,114,116,32,99, + 111,109,112,111,110,101,110,116,115,46,114,27,1,0,0,78, + 41,13,114,32,1,0,0,114,159,0,0,0,114,8,0,0, + 0,114,253,0,0,0,114,147,0,0,0,114,5,1,0,0, + 114,18,1,0,0,114,3,0,0,0,114,109,0,0,0,218, + 9,109,101,116,97,95,112,97,116,104,114,161,0,0,0,114, + 166,0,0,0,114,248,0,0,0,41,2,114,31,1,0,0, + 90,17,115,117,112,112,111,114,116,101,100,95,108,111,97,100, + 101,114,115,114,4,0,0,0,114,4,0,0,0,114,6,0, + 0,0,218,8,95,105,110,115,116,97,108,108,157,5,0,0, + 115,12,0,0,0,0,2,8,1,6,1,20,1,10,1,12, + 1,114,34,1,0,0,41,1,114,0,0,0,0,41,2,114, + 1,0,0,0,114,2,0,0,0,41,1,114,49,0,0,0, + 41,1,78,41,3,78,78,78,41,3,78,78,78,41,2,114, + 62,0,0,0,114,62,0,0,0,41,1,78,41,1,78,41, + 58,114,111,0,0,0,114,12,0,0,0,90,37,95,67,65, + 83,69,95,73,78,83,69,78,83,73,84,73,86,69,95,80, + 76,65,84,70,79,82,77,83,95,66,89,84,69,83,95,75, + 69,89,114,11,0,0,0,114,13,0,0,0,114,19,0,0, + 0,114,21,0,0,0,114,30,0,0,0,114,40,0,0,0, + 114,41,0,0,0,114,45,0,0,0,114,46,0,0,0,114, + 48,0,0,0,114,58,0,0,0,218,4,116,121,112,101,218, + 8,95,95,99,111,100,101,95,95,114,142,0,0,0,114,17, + 0,0,0,114,132,0,0,0,114,16,0,0,0,114,20,0, + 0,0,90,17,95,82,65,87,95,77,65,71,73,67,95,78, + 85,77,66,69,82,114,77,0,0,0,114,76,0,0,0,114, + 88,0,0,0,114,78,0,0,0,90,23,68,69,66,85,71, + 95,66,89,84,69,67,79,68,69,95,83,85,70,70,73,88, + 69,83,90,27,79,80,84,73,77,73,90,69,68,95,66,89, + 84,69,67,79,68,69,95,83,85,70,70,73,88,69,83,114, + 83,0,0,0,114,89,0,0,0,114,95,0,0,0,114,99, + 0,0,0,114,101,0,0,0,114,120,0,0,0,114,127,0, + 0,0,114,139,0,0,0,114,145,0,0,0,114,148,0,0, + 0,114,153,0,0,0,218,6,111,98,106,101,99,116,114,160, + 0,0,0,114,165,0,0,0,114,166,0,0,0,114,181,0, + 0,0,114,191,0,0,0,114,207,0,0,0,114,215,0,0, + 0,114,220,0,0,0,114,226,0,0,0,114,221,0,0,0, + 114,227,0,0,0,114,246,0,0,0,114,248,0,0,0,114, + 5,1,0,0,114,23,1,0,0,114,159,0,0,0,114,32, + 1,0,0,114,34,1,0,0,114,4,0,0,0,114,4,0, + 0,0,114,4,0,0,0,114,6,0,0,0,218,8,60,109, + 111,100,117,108,101,62,8,0,0,0,115,108,0,0,0,4, + 16,4,1,4,1,2,1,6,3,8,17,8,5,8,5,8, + 6,8,12,8,10,8,9,8,5,8,7,10,22,10,122,16, + 1,12,2,4,1,4,2,6,2,6,2,8,2,16,45,8, + 34,8,19,8,12,8,12,8,28,8,17,10,55,10,12,10, + 10,8,14,6,3,4,1,14,67,14,64,14,29,16,110,14, + 41,18,45,18,16,4,3,18,53,14,60,14,42,14,127,0, + 5,14,127,0,22,10,23,8,11,8,68, }; diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -704,11 +704,11 @@ /* Remove unreachable ops after RETURN */ case RETURN_VALUE: h = i + 1; - while (h + 1 < codelen && ISBASICBLOCK(blocks, i, h + 1)) { + while (h < codelen && ISBASICBLOCK(blocks, i, h)) { h++; } if (h > i + 1) { - fill_nops(codestr, i + 1, h + 1); + fill_nops(codestr, i + 1, h); nexti = find_op(codestr, h); } break; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:47:02 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 06:47:02 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI3MDI1?= =?utf-8?q?=3A_Generated_names_for_Tkinter_widgets_now_start_by_the_=22!?= =?utf-8?q?=22_prefix?= Message-ID: <20161025064702.9443.21225.3BB79FB2@psf.io> https://hg.python.org/cpython/rev/603ac788ed27 changeset: 104688:603ac788ed27 branch: 3.6 parent: 104686:5784cc37b5f4 user: Serhiy Storchaka date: Tue Oct 25 09:43:48 2016 +0300 summary: Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix for readability (was "`"). files: Lib/tkinter/__init__.py | 4 ++-- Misc/NEWS | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2261,9 +2261,9 @@ count = master._last_child_ids.get(name, 0) + 1 master._last_child_ids[name] = count if count == 1: - name = '`%s' % (name,) + name = '!%s' % (name,) else: - name = '`%s%d' % (name, count) + name = '!%s%d' % (name, count) self._name = name if master._w=='.': self._w = '.' + name diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,9 @@ Library ------- +- Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix + for readability (was "`"). + - Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin a workaround to Tix library bug. @@ -1339,6 +1342,9 @@ exposed on the API which are not implemented on GNU/Hurd. They would not work at runtime anyway. +- Issue #27025: Generated names for Tkinter widgets are now more meanful + and recognizirable. + - Issue #25455: Fixed crashes in repr of recursive ElementTree.Element and functools.partial objects. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:47:02 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 06:47:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327025=3A_Generated_names_for_Tkinter_widgets_no?= =?utf-8?q?w_start_by_the_=22!=22_prefix?= Message-ID: <20161025064702.9377.47620.4A130EC5@psf.io> https://hg.python.org/cpython/rev/505949cb2692 changeset: 104689:505949cb2692 parent: 104687:8d571fab4d66 parent: 104688:603ac788ed27 user: Serhiy Storchaka date: Tue Oct 25 09:46:46 2016 +0300 summary: Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix for readability (was "`"). files: Lib/tkinter/__init__.py | 4 +- Misc/NEWS | 156 ++++++++++++++------------- 2 files changed, 83 insertions(+), 77 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2261,9 +2261,9 @@ count = master._last_child_ids.get(name, 0) + 1 master._last_child_ids[name] = count if count == 1: - name = '`%s' % (name,) + name = '!%s' % (name,) else: - name = '`%s%d' % (name, count) + name = '!%s%d' % (name, count) self._name = name if master._w=='.': self._w = '.' + name diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,84 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). +- Issue #28183: Optimize and cleanup dict iteration. + +- Issue #26081: Added C implementation of asyncio.Future. + Original patch by Yury Selivanov. + +- Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). + Patch by Xiang Zhang. + +- Issue #28376: The type of long range iterator is now registered as Iterator. + Patch by Oren Milman. + +- Issue #28376: Creating instances of range_iterator by calling range_iterator + type now is disallowed. Calling iter() on range instance is the only way. + Patch by Oren Milman. + +- Issue #26906: Resolving special methods of uninitialized type now causes + implicit initialization of the type instead of a fail. + +- Issue #18287: PyType_Ready() now checks that tp_name is not NULL. + Original patch by Niklas Koep. + +- Issue #24098: Fixed possible crash when AST is changed in process of + compiling it. + +- Issue #28201: Dict reduces possibility of 2nd conflict in hash table when + hashes have same lower bits. + +- Issue #28350: String constants with null character no longer interned. + +- Issue #26617: Fix crash when GC runs during weakref callbacks. + +- Issue #27942: String constants now interned recursively in tuples and frozensets. + +- Issue #28289: ImportError.__init__ now resets not specified attributes. + +- Issue #21578: Fixed misleading error message when ImportError called with + invalid keyword args. + +- Issue #28203: Fix incorrect type in complex(1.0, {2:3}) error message. + Patch by Soumya Sharma. + +- Issue #28086: Single var-positional argument of tuple subtype was passed + unscathed to the C-defined function. Now it is converted to exact tuple. + +- Issue #28214: Now __set_name__ is looked up on the class instead of the + instance. + +- Issue #27955: Fallback on reading /dev/urandom device when the getrandom() + syscall fails with EPERM, for example when blocked by SECCOMP. + +- Issue #28192: Don't import readline in isolated mode. + +- Issue #27441: Remove some redundant assignments to ob_size in longobject.c. + Thanks Oren Milman. + +- Issue #27222: Clean up redundant code in long_rshift function. Thanks + Oren Milman. + +- Upgrade internal unicode databases to Unicode version 9.0.0. + +- Issue #28131: Fix a regression in zipimport's compile_source(). zipimport + should use the same optimization level as the interpreter. + +- Issue #28126: Replace Py_MEMCPY with memcpy(). Visual Studio can properly + optimize memcpy(). + +- Issue #28120: Fix dict.pop() for splitted dictionary when trying to remove a + "pending key" (Not yet inserted in split-table). Patch by Xiang Zhang. + +- Issue #26182: Raise DeprecationWarning when async and await keywords are + used as variable/attribute/class/function name. + +Library +------- + +- Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix + for readability (was "`"). + - Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin a workaround to Tix library bug. @@ -30,81 +108,6 @@ group index and the position of the reference. Based on patch by SilentGhost. -- Issue #28183: Optimize and cleanup dict iteration. - -- Issue #26081: Added C implementation of asyncio.Future. - Original patch by Yury Selivanov. - -- Issue #28379: Added sanity checks and tests for PyUnicode_CopyCharacters(). - Patch by Xiang Zhang. - -- Issue #28376: The type of long range iterator is now registered as Iterator. - Patch by Oren Milman. - -- Issue #28376: Creating instances of range_iterator by calling range_iterator - type now is disallowed. Calling iter() on range instance is the only way. - Patch by Oren Milman. - -- Issue #26906: Resolving special methods of uninitialized type now causes - implicit initialization of the type instead of a fail. - -- Issue #18287: PyType_Ready() now checks that tp_name is not NULL. - Original patch by Niklas Koep. - -- Issue #24098: Fixed possible crash when AST is changed in process of - compiling it. - -- Issue #28201: Dict reduces possibility of 2nd conflict in hash table when - hashes have same lower bits. - -- Issue #28350: String constants with null character no longer interned. - -- Issue #26617: Fix crash when GC runs during weakref callbacks. - -- Issue #27942: String constants now interned recursively in tuples and frozensets. - -- Issue #28289: ImportError.__init__ now resets not specified attributes. - -- Issue #21578: Fixed misleading error message when ImportError called with - invalid keyword args. - -- Issue #28203: Fix incorrect type in complex(1.0, {2:3}) error message. - Patch by Soumya Sharma. - -- Issue #28086: Single var-positional argument of tuple subtype was passed - unscathed to the C-defined function. Now it is converted to exact tuple. - -- Issue #28214: Now __set_name__ is looked up on the class instead of the - instance. - -- Issue #27955: Fallback on reading /dev/urandom device when the getrandom() - syscall fails with EPERM, for example when blocked by SECCOMP. - -- Issue #28192: Don't import readline in isolated mode. - -- Issue #27441: Remove some redundant assignments to ob_size in longobject.c. - Thanks Oren Milman. - -- Issue #27222: Clean up redundant code in long_rshift function. Thanks - Oren Milman. - -- Upgrade internal unicode databases to Unicode version 9.0.0. - -- Issue #28131: Fix a regression in zipimport's compile_source(). zipimport - should use the same optimization level as the interpreter. - -- Issue #28126: Replace Py_MEMCPY with memcpy(). Visual Studio can properly - optimize memcpy(). - -- Issue #28120: Fix dict.pop() for splitted dictionary when trying to remove a - "pending key" (Not yet inserted in split-table). Patch by Xiang Zhang. - -- Issue #26182: Raise DeprecationWarning when async and await keywords are - used as variable/attribute/class/function name. - -Library -------- - - Issue #28469: timeit now uses the sequence 1, 2, 5, 10, 20, 50,... instead of 1, 10, 100,... for autoranging. @@ -1364,6 +1367,9 @@ exposed on the API which are not implemented on GNU/Hurd. They would not work at runtime anyway. +- Issue #27025: Generated names for Tkinter widgets are now more meanful + and recognizirable. + - Issue #25455: Fixed crashes in repr of recursive ElementTree.Element and functools.partial objects. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 02:51:57 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 06:51:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4NTE1?= =?utf-8?q?=3A_Fixed_py3k_warnings=2E?= Message-ID: <20161025065157.68370.7491.E16E9737@psf.io> https://hg.python.org/cpython/rev/77571b528f6a changeset: 104690:77571b528f6a branch: 2.7 parent: 104679:f57078cf5f13 user: Serhiy Storchaka date: Tue Oct 25 09:51:38 2016 +0300 summary: Issue #28515: Fixed py3k warnings. files: Lib/lib-tk/turtle.py | 3 ++- Lib/test/pickletester.py | 3 +++ Lib/wave.py | 2 +- Tools/scripts/fixcid.py | 8 ++++---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/lib-tk/turtle.py b/Lib/lib-tk/turtle.py --- a/Lib/lib-tk/turtle.py +++ b/Lib/lib-tk/turtle.py @@ -728,10 +728,11 @@ """ return self.cv.create_image(0, 0, image=image) - def _drawimage(self, item, (x, y), image): + def _drawimage(self, item, pos, image): """Configure image item as to draw image object at position (x,y) on canvas) """ + x, y = pos self.cv.coords(item, (x * self.xscale, -y * self.yscale)) self.cv.itemconfig(item, image=image) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1572,6 +1572,7 @@ self.items = items def __eq__(self, other): return type(self) is type(other) and self.items == other.items + __hash__ = None def append(self, item): self.items.append(item) def extend(self, items): @@ -1590,6 +1591,7 @@ self.table = table def __eq__(self, other): return type(self) is type(other) and self.table == other.table + __hash__ = None def __setitem__(self, key, value): self.table[key] = value def __reduce__(self): @@ -1639,6 +1641,7 @@ raise TypeError("SimpleNewObj.__init__() didn't expect to get called") def __eq__(self, other): return int(self) == int(other) and self.__dict__ == other.__dict__ + __hash__ = None class ComplexNewObj(SimpleNewObj): def __getnewargs__(self): diff --git a/Lib/wave.py b/Lib/wave.py --- a/Lib/wave.py +++ b/Lib/wave.py @@ -243,7 +243,7 @@ assert data.itemsize == self._sampwidth nitems = nframes * self._nchannels if nitems * self._sampwidth > chunk.chunksize - chunk.size_read: - nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth + nitems = (chunk.chunksize - chunk.size_read) // self._sampwidth data.fromfile(chunk.file.file, nitems) # "tell" data chunk how much was read chunk.size_read = chunk.size_read + nitems * self._sampwidth diff --git a/Tools/scripts/fixcid.py b/Tools/scripts/fixcid.py --- a/Tools/scripts/fixcid.py +++ b/Tools/scripts/fixcid.py @@ -242,14 +242,14 @@ elif found == '*/': Program = OutsideCommentProgram n = len(found) - if Dict.has_key(found): + if found in Dict: subst = Dict[found] if Program is InsideCommentProgram: if not Docomments: print 'Found in comment:', found i = i + n continue - if NotInComment.has_key(found): + if found in NotInComment: ## print 'Ignored in comment:', ## print found, '-->', subst ## print 'Line:', line, @@ -294,7 +294,7 @@ if not words: continue if len(words) == 3 and words[0] == 'struct': words[:2] = [words[0] + ' ' + words[1]] - elif len(words) <> 2: + elif len(words) != 2: err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line)) continue if Reverse: @@ -306,7 +306,7 @@ if key[0] == '*': key = key[1:] NotInComment[key] = value - if Dict.has_key(key): + if key in Dict: err('%s:%r: warning: overriding: %r %r\n' % (substfile, lineno, key, value)) err('%s:%r: warning: previous: %r\n' % (substfile, lineno, Dict[key])) Dict[key] = value -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:18:50 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:18:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328426=3A_Fixed_potential_crash_in_PyUnicode=5FAsDecod?= =?utf-8?q?edObject=28=29_in_debug?= Message-ID: <20161025071849.11996.74085.3C72D25C@psf.io> https://hg.python.org/cpython/rev/6af1a26e655f changeset: 104693:6af1a26e655f branch: 3.6 parent: 104688:603ac788ed27 parent: 104692:74569ecd67e4 user: Serhiy Storchaka date: Tue Oct 25 10:17:33 2016 +0300 summary: Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug build. files: Misc/NEWS | 3 +++ Objects/unicodeobject.c | 12 ++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug + build. + - Issue #28517: Fixed of-by-one error in the peephole optimizer that caused keeping unreachable code. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3236,24 +3236,16 @@ const char *encoding, const char *errors) { - PyObject *v; - if (!PyUnicode_Check(unicode)) { PyErr_BadArgument(); - goto onError; + return NULL; } if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Decode via the codec registry */ - v = PyCodec_Decode(unicode, encoding, errors); - if (v == NULL) - goto onError; - return unicode_result(v); - - onError: - return NULL; + return PyCodec_Decode(unicode, encoding, errors); } PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:18:56 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:18:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzI4NDI2?= =?utf-8?q?=3A_Fixed_potential_crash_in_PyUnicode=5FAsDecodedObject=28=29_?= =?utf-8?q?in_debug?= Message-ID: <20161025071849.27199.84563.5BD61738@psf.io> https://hg.python.org/cpython/rev/71dce630dc02 changeset: 104691:71dce630dc02 branch: 3.4 parent: 104448:d7b9ce8ae79b user: Serhiy Storchaka date: Tue Oct 25 10:07:51 2016 +0300 summary: Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug build. files: Misc/NEWS | 3 +++ Objects/unicodeobject.c | 12 ++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug + build. + Library ------- diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3059,24 +3059,16 @@ const char *encoding, const char *errors) { - PyObject *v; - if (!PyUnicode_Check(unicode)) { PyErr_BadArgument(); - goto onError; + return NULL; } if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Decode via the codec registry */ - v = PyCodec_Decode(unicode, encoding, errors); - if (v == NULL) - goto onError; - return unicode_result(v); - - onError: - return NULL; + return PyCodec_Decode(unicode, encoding, errors); } PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:18:56 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:18:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328426=3A_Fixed_potential_crash_in_PyUnicode=5FA?= =?utf-8?q?sDecodedObject=28=29_in_debug?= Message-ID: <20161025071849.9357.48975.A6C5DCAB@psf.io> https://hg.python.org/cpython/rev/1ab1fd00e9d6 changeset: 104694:1ab1fd00e9d6 parent: 104689:505949cb2692 parent: 104693:6af1a26e655f user: Serhiy Storchaka date: Tue Oct 25 10:18:16 2016 +0300 summary: Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug build. files: Misc/NEWS | 3 +++ Objects/unicodeobject.c | 12 ++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug + build. + - Issue #28517: Fixed of-by-one error in the peephole optimizer that caused keeping unreachable code. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3232,24 +3232,16 @@ const char *encoding, const char *errors) { - PyObject *v; - if (!PyUnicode_Check(unicode)) { PyErr_BadArgument(); - goto onError; + return NULL; } if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Decode via the codec registry */ - v = PyCodec_Decode(unicode, encoding, errors); - if (v == NULL) - goto onError; - return unicode_result(v); - - onError: - return NULL; + return PyCodec_Decode(unicode, encoding, errors); } PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:18:56 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:18:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNSk6?= =?utf-8?q?_Issue_=2328426=3A_Fixed_potential_crash_in_PyUnicode=5FAsDecod?= =?utf-8?q?edObject=28=29_in_debug?= Message-ID: <20161025071849.25195.76872.08A60DA0@psf.io> https://hg.python.org/cpython/rev/74569ecd67e4 changeset: 104692:74569ecd67e4 branch: 3.5 parent: 104683:05b5e1aaedc5 parent: 104691:71dce630dc02 user: Serhiy Storchaka date: Tue Oct 25 10:13:43 2016 +0300 summary: Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug build. files: Misc/NEWS | 3 +++ Objects/unicodeobject.c | 12 ++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug + build. + - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3026,24 +3026,16 @@ const char *encoding, const char *errors) { - PyObject *v; - if (!PyUnicode_Check(unicode)) { PyErr_BadArgument(); - goto onError; + return NULL; } if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Decode via the codec registry */ - v = PyCodec_Decode(unicode, encoding, errors); - if (v == NULL) - goto onError; - return unicode_result(v); - - onError: - return NULL; + return PyCodec_Decode(unicode, encoding, errors); } PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:38:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:38:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328314=3A_Added_tests_for_xml=2Eetree=2EElementT?= =?utf-8?q?ree=2EElement=2Egetiterator=28=29=2E?= Message-ID: <20161025073821.11759.1484.4888C864@psf.io> https://hg.python.org/cpython/rev/17334c1d9245 changeset: 104697:17334c1d9245 parent: 104694:1ab1fd00e9d6 parent: 104696:c14a2d2a3b19 user: Serhiy Storchaka date: Tue Oct 25 10:38:07 2016 +0300 summary: Issue #28314: Added tests for xml.etree.ElementTree.Element.getiterator(). files: Lib/test/test_xml_etree.py | 32 ++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2195,9 +2195,41 @@ # make sure both tag=None and tag='*' return all tags all_tags = ['document', 'house', 'room', 'room', 'shed', 'house', 'room'] + self.assertEqual(summarize_list(doc.iter()), all_tags) self.assertEqual(self._ilist(doc), all_tags) self.assertEqual(self._ilist(doc, '*'), all_tags) + def test_getiterator(self): + doc = ET.XML(''' + + + bedroom1 + bedroom2 + + nothing here + + + bedroom8 + + ''') + + self.assertEqual(summarize_list(doc.getiterator('room')), + ['room'] * 3) + self.assertEqual(summarize_list(doc.getiterator('house')), + ['house'] * 2) + + # test that getiterator also accepts 'tag' as a keyword arg + self.assertEqual( + summarize_list(doc.getiterator(tag='room')), + ['room'] * 3) + + # make sure both tag=None and tag='*' return all tags + all_tags = ['document', 'house', 'room', 'room', + 'shed', 'house', 'room'] + self.assertEqual(summarize_list(doc.getiterator()), all_tags) + self.assertEqual(summarize_list(doc.getiterator(None)), all_tags) + self.assertEqual(summarize_list(doc.getiterator('*')), all_tags) + def test_copy(self): a = ET.Element('a') it = a.iter() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:38:24 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:38:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzE0?= =?utf-8?q?=3A_Added_tests_for_xml=2Eetree=2EElementTree=2EElement=2Egetit?= =?utf-8?b?ZXJhdG9yKCku?= Message-ID: <20161025073820.9330.63131.D081A0DA@psf.io> https://hg.python.org/cpython/rev/ca1b91829edf changeset: 104695:ca1b91829edf branch: 3.5 parent: 104692:74569ecd67e4 user: Serhiy Storchaka date: Tue Oct 25 10:37:01 2016 +0300 summary: Issue #28314: Added tests for xml.etree.ElementTree.Element.getiterator(). files: Lib/test/test_xml_etree.py | 32 ++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2191,9 +2191,41 @@ # make sure both tag=None and tag='*' return all tags all_tags = ['document', 'house', 'room', 'room', 'shed', 'house', 'room'] + self.assertEqual(summarize_list(doc.iter()), all_tags) self.assertEqual(self._ilist(doc), all_tags) self.assertEqual(self._ilist(doc, '*'), all_tags) + def test_getiterator(self): + doc = ET.XML(''' + + + bedroom1 + bedroom2 + + nothing here + + + bedroom8 + + ''') + + self.assertEqual(summarize_list(doc.getiterator('room')), + ['room'] * 3) + self.assertEqual(summarize_list(doc.getiterator('house')), + ['house'] * 2) + + # test that getiterator also accepts 'tag' as a keyword arg + self.assertEqual( + summarize_list(doc.getiterator(tag='room')), + ['room'] * 3) + + # make sure both tag=None and tag='*' return all tags + all_tags = ['document', 'house', 'room', 'room', + 'shed', 'house', 'room'] + self.assertEqual(summarize_list(doc.getiterator()), all_tags) + self.assertEqual(summarize_list(doc.getiterator(None)), all_tags) + self.assertEqual(summarize_list(doc.getiterator('*')), all_tags) + def test_copy(self): a = ET.Element('a') it = a.iter() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 03:38:24 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 07:38:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328314=3A_Added_tests_for_xml=2Eetree=2EElementTree=2E?= =?utf-8?q?Element=2Egetiterator=28=29=2E?= Message-ID: <20161025073820.27199.90060.AA69EBB9@psf.io> https://hg.python.org/cpython/rev/c14a2d2a3b19 changeset: 104696:c14a2d2a3b19 branch: 3.6 parent: 104693:6af1a26e655f parent: 104695:ca1b91829edf user: Serhiy Storchaka date: Tue Oct 25 10:37:55 2016 +0300 summary: Issue #28314: Added tests for xml.etree.ElementTree.Element.getiterator(). files: Lib/test/test_xml_etree.py | 32 ++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2195,9 +2195,41 @@ # make sure both tag=None and tag='*' return all tags all_tags = ['document', 'house', 'room', 'room', 'shed', 'house', 'room'] + self.assertEqual(summarize_list(doc.iter()), all_tags) self.assertEqual(self._ilist(doc), all_tags) self.assertEqual(self._ilist(doc, '*'), all_tags) + def test_getiterator(self): + doc = ET.XML(''' + + + bedroom1 + bedroom2 + + nothing here + + + bedroom8 + + ''') + + self.assertEqual(summarize_list(doc.getiterator('room')), + ['room'] * 3) + self.assertEqual(summarize_list(doc.getiterator('house')), + ['house'] * 2) + + # test that getiterator also accepts 'tag' as a keyword arg + self.assertEqual( + summarize_list(doc.getiterator(tag='room')), + ['room'] * 3) + + # make sure both tag=None and tag='*' return all tags + all_tags = ['document', 'house', 'room', 'room', + 'shed', 'house', 'room'] + self.assertEqual(summarize_list(doc.getiterator()), all_tags) + self.assertEqual(summarize_list(doc.getiterator(None)), all_tags) + self.assertEqual(summarize_list(doc.getiterator('*')), all_tags) + def test_copy(self): a = ET.Element('a') it = a.iter() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:11:58 2016 From: python-checkins at python.org (inada.naoki) Date: Tue, 25 Oct 2016 10:11:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328430=3A_Fix_iterator_of_C_implemented_asyncio?= =?utf-8?q?=2EFuture_doesn=27t?= Message-ID: <20161025101150.25381.84411.28169F0D@psf.io> https://hg.python.org/cpython/rev/bd141ec2973a changeset: 104699:bd141ec2973a parent: 104697:17334c1d9245 parent: 104698:b471447352ac user: INADA Naoki date: Tue Oct 25 19:11:40 2016 +0900 summary: Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept non-None value is passed to it.send(val). files: Misc/NEWS | 3 +++ Modules/_asynciomodule.c | 10 ++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ Library ------- +- Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept + non-None value is passed to it.send(val). + - Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix for readability (was "`"). diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -815,13 +815,11 @@ } static PyObject * -FutureIter_send(futureiterobject *self, PyObject *arg) +FutureIter_send(futureiterobject *self, PyObject *unused) { - if (arg != Py_None) { - PyErr_Format(PyExc_TypeError, - "can't send non-None value to a FutureIter"); - return NULL; - } + /* Future.__iter__ doesn't care about values that are pushed to the + * generator, it just returns "self.result(). + */ return FutureIter_iternext(self); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:11:58 2016 From: python-checkins at python.org (inada.naoki) Date: Tue, 25 Oct 2016 10:11:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDMw?= =?utf-8?q?=3A_Fix_iterator_of_C_implemented_asyncio=2EFuture_doesn=27t?= Message-ID: <20161025101150.17963.14233.9BCAAE23@psf.io> https://hg.python.org/cpython/rev/b471447352ac changeset: 104698:b471447352ac branch: 3.6 parent: 104696:c14a2d2a3b19 user: INADA Naoki date: Tue Oct 25 19:00:45 2016 +0900 summary: Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept non-None value is passed to it.send(val). files: Misc/NEWS | 3 +++ Modules/_asynciomodule.c | 10 ++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,9 @@ Library ------- +- Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept + non-None value is passed to it.send(val). + - Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix for readability (was "`"). diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -815,13 +815,11 @@ } static PyObject * -FutureIter_send(futureiterobject *self, PyObject *arg) +FutureIter_send(futureiterobject *self, PyObject *unused) { - if (arg != Py_None) { - PyErr_Format(PyExc_TypeError, - "can't send non-None value to a FutureIter"); - return NULL; - } + /* Future.__iter__ doesn't care about values that are pushed to the + * generator, it just returns "self.result(). + */ return FutureIter_iternext(self); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:48:18 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 10:48:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328408=3A_Fixed_a_leak_and_remove_redundant_code?= =?utf-8?q?_in?= Message-ID: <20161025104818.25381.13578.FA7D862D@psf.io> https://hg.python.org/cpython/rev/24c3f997bd1a changeset: 104701:24c3f997bd1a parent: 104697:17334c1d9245 parent: 104700:9d618cebfc21 user: Serhiy Storchaka date: Tue Oct 25 13:25:04 2016 +0300 summary: Issue #28408: Fixed a leak and remove redundant code in _PyUnicodeWriter_Finish(). Patch by Xiang Zhang. files: Objects/unicodeobject.c | 34 +++++++++++----------------- 1 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13551,34 +13551,28 @@ _PyUnicodeWriter_Finish(_PyUnicodeWriter *writer) { PyObject *str; + if (writer->pos == 0) { Py_CLEAR(writer->buffer); _Py_RETURN_UNICODE_EMPTY(); } + + str = writer->buffer; + writer->buffer = NULL; + if (writer->readonly) { - str = writer->buffer; - writer->buffer = NULL; assert(PyUnicode_GET_LENGTH(str) == writer->pos); return str; } - if (writer->pos == 0) { - Py_CLEAR(writer->buffer); - - /* Get the empty Unicode string singleton ('') */ - _Py_INCREF_UNICODE_EMPTY(); - str = unicode_empty; - } - else { - str = writer->buffer; - writer->buffer = NULL; - - if (PyUnicode_GET_LENGTH(str) != writer->pos) { - PyObject *str2; - str2 = resize_compact(str, writer->pos); - if (str2 == NULL) - return NULL; - str = str2; - } + + if (PyUnicode_GET_LENGTH(str) != writer->pos) { + PyObject *str2; + str2 = resize_compact(str, writer->pos); + if (str2 == NULL) { + Py_DECREF(str); + return NULL; + } + str = str2; } assert(_PyUnicode_CheckConsistency(str, 1)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:48:18 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 10:48:18 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDA4?= =?utf-8?q?=3A_Fixed_a_leak_and_remove_redundant_code_in?= Message-ID: <20161025104818.18394.85535.ECADB303@psf.io> https://hg.python.org/cpython/rev/9d618cebfc21 changeset: 104700:9d618cebfc21 branch: 3.6 parent: 104696:c14a2d2a3b19 user: Serhiy Storchaka date: Tue Oct 25 13:23:56 2016 +0300 summary: Issue #28408: Fixed a leak and remove redundant code in _PyUnicodeWriter_Finish(). Patch by Xiang Zhang. files: Objects/unicodeobject.c | 34 +++++++++++----------------- 1 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13570,34 +13570,28 @@ _PyUnicodeWriter_Finish(_PyUnicodeWriter *writer) { PyObject *str; + if (writer->pos == 0) { Py_CLEAR(writer->buffer); _Py_RETURN_UNICODE_EMPTY(); } + + str = writer->buffer; + writer->buffer = NULL; + if (writer->readonly) { - str = writer->buffer; - writer->buffer = NULL; assert(PyUnicode_GET_LENGTH(str) == writer->pos); return str; } - if (writer->pos == 0) { - Py_CLEAR(writer->buffer); - - /* Get the empty Unicode string singleton ('') */ - _Py_INCREF_UNICODE_EMPTY(); - str = unicode_empty; - } - else { - str = writer->buffer; - writer->buffer = NULL; - - if (PyUnicode_GET_LENGTH(str) != writer->pos) { - PyObject *str2; - str2 = resize_compact(str, writer->pos); - if (str2 == NULL) - return NULL; - str = str2; - } + + if (PyUnicode_GET_LENGTH(str) != writer->pos) { + PyObject *str2; + str2 = resize_compact(str, writer->pos); + if (str2 == NULL) { + Py_DECREF(str); + return NULL; + } + str = str2; } assert(_PyUnicode_CheckConsistency(str, 1)); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:48:19 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 10:48:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy42IC0+IDMuNik6?= =?utf-8?q?_Merge_heads?= Message-ID: <20161025104819.17005.11495.A6C94C21@psf.io> https://hg.python.org/cpython/rev/38890b86f11c changeset: 104702:38890b86f11c branch: 3.6 parent: 104700:9d618cebfc21 parent: 104698:b471447352ac user: Serhiy Storchaka date: Tue Oct 25 13:47:41 2016 +0300 summary: Merge heads files: Misc/NEWS | 3 +++ Modules/_asynciomodule.c | 10 ++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,9 @@ Library ------- +- Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept + non-None value is passed to it.send(val). + - Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix for readability (was "`"). diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -815,13 +815,11 @@ } static PyObject * -FutureIter_send(futureiterobject *self, PyObject *arg) +FutureIter_send(futureiterobject *self, PyObject *unused) { - if (arg != Py_None) { - PyErr_Format(PyExc_TypeError, - "can't send non-None value to a FutureIter"); - return NULL; - } + /* Future.__iter__ doesn't care about values that are pushed to the + * generator, it just returns "self.result(). + */ return FutureIter_iternext(self); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:48:19 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 10:48:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <20161025104819.38693.8309.1231A596@psf.io> https://hg.python.org/cpython/rev/9910ce2009bd changeset: 104703:9910ce2009bd parent: 104701:24c3f997bd1a parent: 104699:bd141ec2973a user: Serhiy Storchaka date: Tue Oct 25 13:47:55 2016 +0300 summary: Merge heads files: Misc/NEWS | 3 +++ Modules/_asynciomodule.c | 10 ++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ Library ------- +- Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept + non-None value is passed to it.send(val). + - Issue #27025: Generated names for Tkinter widgets now start by the "!" prefix for readability (was "`"). diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -815,13 +815,11 @@ } static PyObject * -FutureIter_send(futureiterobject *self, PyObject *arg) +FutureIter_send(futureiterobject *self, PyObject *unused) { - if (arg != Py_None) { - PyErr_Format(PyExc_TypeError, - "can't send non-None value to a FutureIter"); - return NULL; - } + /* Future.__iter__ doesn't care about values that are pushed to the + * generator, it just returns "self.result(). + */ return FutureIter_iternext(self); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 06:48:19 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 10:48:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161025104819.17963.14222.4583E1CF@psf.io> https://hg.python.org/cpython/rev/ead3600afd02 changeset: 104704:ead3600afd02 parent: 104703:9910ce2009bd parent: 104702:38890b86f11c user: Serhiy Storchaka date: Tue Oct 25 13:48:04 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Tue Oct 25 07:15:28 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 25 Oct 2016 12:15:28 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-25 Message-ID: Results for project Python 2.7, build date 2016-10-25 02:48:03 +0000 commit: f57078cf5f13 previous commit: 7f01d9d471e5 revision date: 2016-10-24 20:47:08 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.18% -0.94% 4.05% 6.79% :-) pybench 0.19% -0.14% 5.95% 3.78% :-( regex_v8 0.66% -0.02% -2.06% 10.65% :-) nbody 0.13% 0.03% 7.89% 4.25% :-) json_dump_v2 0.32% -0.07% 2.65% 9.59% :-| normal_startup 0.86% 0.53% -0.15% 1.92% :-) ssbench 0.15% -0.13% 2.03% 1.55% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-25/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Tue Oct 25 07:19:03 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 25 Oct 2016 12:19:03 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-25 Message-ID: Results for project Python default, build date 2016-10-25 02:01:48 +0000 commit: 5b33829badcc previous commit: 3e7da46aead3 revision date: 2016-10-24 20:49:51 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.18% -0.44% 5.36% 14.06% :-) pybench 0.10% 0.07% 5.51% 5.18% :-( regex_v8 3.85% 0.00% -4.08% 4.21% :-) nbody 0.11% -0.01% 2.06% 4.19% :-( json_dump_v2 0.24% 1.40% -9.30% 15.29% :-| normal_startup 0.84% 0.08% 0.40% 5.83% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-25/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Tue Oct 25 07:35:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 11:35:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzUz?= =?utf-8?q?=3A_os=2Efwalk=28=29_no_longer_fails_on_broken_links=2E?= Message-ID: <20161025113533.12089.76444.5C2AAE77@psf.io> https://hg.python.org/cpython/rev/fe1fea4ded04 changeset: 104705:fe1fea4ded04 branch: 3.5 parent: 104695:ca1b91829edf user: Serhiy Storchaka date: Tue Oct 25 14:28:38 2016 +0300 summary: Issue #28353: os.fwalk() no longer fails on broken links. files: Lib/os.py | 4 ++-- Lib/test/test_os.py | 26 +++++++++++++++++++++----- Misc/NEWS | 2 ++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -537,13 +537,13 @@ dirs.append(name) else: nondirs.append(name) - except FileNotFoundError: + except OSError: try: # Add dangling symlinks, ignore disappeared files if st.S_ISLNK(stat(name, dir_fd=topfd, follow_symlinks=False) .st_mode): nondirs.append(name) - except FileNotFoundError: + except OSError: continue if topdown: 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 @@ -830,39 +830,53 @@ # SUB11/ no kids # SUB2/ a file kid and a dirsymlink kid # tmp3 + # SUB21/ not readable + # tmp5 # link/ a symlink to TESTFN.2 # broken_link + # broken_link2 + # broken_link3 # TEST2/ # tmp4 a lone file self.walk_path = join(support.TESTFN, "TEST1") self.sub1_path = join(self.walk_path, "SUB1") self.sub11_path = join(self.sub1_path, "SUB11") sub2_path = join(self.walk_path, "SUB2") + self.sub21_path = join(sub2_path, "SUB21") tmp1_path = join(self.walk_path, "tmp1") tmp2_path = join(self.sub1_path, "tmp2") tmp3_path = join(sub2_path, "tmp3") + tmp5_path = join(self.sub21_path, "tmp3") self.link_path = join(sub2_path, "link") t2_path = join(support.TESTFN, "TEST2") tmp4_path = join(support.TESTFN, "TEST2", "tmp4") broken_link_path = join(sub2_path, "broken_link") + broken_link2_path = join(sub2_path, "broken_link2") + broken_link3_path = join(sub2_path, "broken_link3") # Create stuff. os.makedirs(self.sub11_path) os.makedirs(sub2_path) + os.makedirs(self.sub21_path) os.makedirs(t2_path) - for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: - f = open(path, "w") - f.write("I'm " + path + " and proud of it. Blame test_os.\n") - f.close() + for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path, tmp5_path: + with open(path, "x") as f: + f.write("I'm " + path + " and proud of it. Blame test_os.\n") if support.can_symlink(): os.symlink(os.path.abspath(t2_path), self.link_path) os.symlink('broken', broken_link_path, True) - self.sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) + os.symlink(join('tmp3', 'broken'), broken_link2_path, True) + os.symlink(join('SUB21', 'tmp5'), broken_link3_path, True) + self.sub2_tree = (sub2_path, ["link", "SUB21"], + ["broken_link", "broken_link2", "broken_link3", + "tmp3"]) else: self.sub2_tree = (sub2_path, [], ["tmp3"]) + os.chmod(self.sub21_path, 0) + def test_walk_topdown(self): # Walk top-down. all = list(self.walk(self.walk_path)) @@ -935,6 +949,7 @@ # Windows, which doesn't have a recursive delete command. The # (not so) subtlety is that rmdir will fail unless the dir's # kids are removed first, so bottom up is essential. + os.chmod(self.sub21_path, stat.S_IRWXU) for root, dirs, files in os.walk(support.TESTFN, topdown=False): for name in files: os.remove(os.path.join(root, name)) @@ -1030,6 +1045,7 @@ def tearDown(self): # cleanup + os.chmod(self.sub21_path, stat.S_IRWXU) for root, dirs, files, rootfd in os.fwalk(support.TESTFN, topdown=False): for name in files: os.unlink(name, dir_fd=rootfd) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,8 @@ Library ------- +- Issue #28353: os.fwalk() no longer fails on broken links. + - Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin a workaround to Tix library bug. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 07:35:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 11:35:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328353=3A_os=2Efwalk=28=29_no_longer_fails_on_broken_l?= =?utf-8?q?inks=2E?= Message-ID: <20161025113533.27118.54027.9A294D93@psf.io> https://hg.python.org/cpython/rev/e99ec3c77a63 changeset: 104706:e99ec3c77a63 branch: 3.6 parent: 104702:38890b86f11c parent: 104705:fe1fea4ded04 user: Serhiy Storchaka date: Tue Oct 25 14:34:38 2016 +0300 summary: Issue #28353: os.fwalk() no longer fails on broken links. files: Lib/os.py | 4 ++-- Lib/test/test_os.py | 20 ++++++++++++++++++-- Misc/NEWS | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -481,13 +481,13 @@ dirs.append(name) else: nondirs.append(name) - except FileNotFoundError: + except OSError: try: # Add dangling symlinks, ignore disappeared files if st.S_ISLNK(stat(name, dir_fd=topfd, follow_symlinks=False) .st_mode): nondirs.append(name) - except FileNotFoundError: + except OSError: continue if topdown: 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 @@ -853,38 +853,54 @@ # SUB11/ no kids # SUB2/ a file kid and a dirsymlink kid # tmp3 + # SUB21/ not readable + # tmp5 # link/ a symlink to TESTFN.2 # broken_link + # broken_link2 + # broken_link3 # TEST2/ # tmp4 a lone file self.walk_path = join(support.TESTFN, "TEST1") self.sub1_path = join(self.walk_path, "SUB1") self.sub11_path = join(self.sub1_path, "SUB11") sub2_path = join(self.walk_path, "SUB2") + sub21_path = join(sub2_path, "SUB21") tmp1_path = join(self.walk_path, "tmp1") tmp2_path = join(self.sub1_path, "tmp2") tmp3_path = join(sub2_path, "tmp3") + tmp5_path = join(sub21_path, "tmp3") self.link_path = join(sub2_path, "link") t2_path = join(support.TESTFN, "TEST2") tmp4_path = join(support.TESTFN, "TEST2", "tmp4") broken_link_path = join(sub2_path, "broken_link") + broken_link2_path = join(sub2_path, "broken_link2") + broken_link3_path = join(sub2_path, "broken_link3") # Create stuff. os.makedirs(self.sub11_path) os.makedirs(sub2_path) + os.makedirs(sub21_path) os.makedirs(t2_path) - for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: + for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path, tmp5_path: with open(path, "x") as f: f.write("I'm " + path + " and proud of it. Blame test_os.\n") if support.can_symlink(): os.symlink(os.path.abspath(t2_path), self.link_path) os.symlink('broken', broken_link_path, True) - self.sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) + os.symlink(join('tmp3', 'broken'), broken_link2_path, True) + os.symlink(join('SUB21', 'tmp5'), broken_link3_path, True) + self.sub2_tree = (sub2_path, ["link", "SUB21"], + ["broken_link", "broken_link2", "broken_link3", + "tmp3"]) else: self.sub2_tree = (sub2_path, [], ["tmp3"]) + os.chmod(sub21_path, 0) + self.addCleanup(os.chmod, sub21_path, stat.S_IRWXU) + def test_walk_topdown(self): # Walk top-down. all = list(self.walk(self.walk_path)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,8 @@ Library ------- +- Issue #28353: os.fwalk() no longer fails on broken links. + - Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept non-None value is passed to it.send(val). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 07:35:33 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 11:35:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328353=3A_os=2Efwalk=28=29_no_longer_fails_on_br?= =?utf-8?q?oken_links=2E?= Message-ID: <20161025113533.110825.93787.8BFD0BC6@psf.io> https://hg.python.org/cpython/rev/33a1a3dd0051 changeset: 104707:33a1a3dd0051 parent: 104704:ead3600afd02 parent: 104706:e99ec3c77a63 user: Serhiy Storchaka date: Tue Oct 25 14:35:18 2016 +0300 summary: Issue #28353: os.fwalk() no longer fails on broken links. files: Lib/os.py | 4 ++-- Lib/test/test_os.py | 20 ++++++++++++++++++-- Misc/NEWS | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -481,13 +481,13 @@ dirs.append(name) else: nondirs.append(name) - except FileNotFoundError: + except OSError: try: # Add dangling symlinks, ignore disappeared files if st.S_ISLNK(stat(name, dir_fd=topfd, follow_symlinks=False) .st_mode): nondirs.append(name) - except FileNotFoundError: + except OSError: continue if topdown: 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 @@ -853,38 +853,54 @@ # SUB11/ no kids # SUB2/ a file kid and a dirsymlink kid # tmp3 + # SUB21/ not readable + # tmp5 # link/ a symlink to TESTFN.2 # broken_link + # broken_link2 + # broken_link3 # TEST2/ # tmp4 a lone file self.walk_path = join(support.TESTFN, "TEST1") self.sub1_path = join(self.walk_path, "SUB1") self.sub11_path = join(self.sub1_path, "SUB11") sub2_path = join(self.walk_path, "SUB2") + sub21_path = join(sub2_path, "SUB21") tmp1_path = join(self.walk_path, "tmp1") tmp2_path = join(self.sub1_path, "tmp2") tmp3_path = join(sub2_path, "tmp3") + tmp5_path = join(sub21_path, "tmp3") self.link_path = join(sub2_path, "link") t2_path = join(support.TESTFN, "TEST2") tmp4_path = join(support.TESTFN, "TEST2", "tmp4") broken_link_path = join(sub2_path, "broken_link") + broken_link2_path = join(sub2_path, "broken_link2") + broken_link3_path = join(sub2_path, "broken_link3") # Create stuff. os.makedirs(self.sub11_path) os.makedirs(sub2_path) + os.makedirs(sub21_path) os.makedirs(t2_path) - for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: + for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path, tmp5_path: with open(path, "x") as f: f.write("I'm " + path + " and proud of it. Blame test_os.\n") if support.can_symlink(): os.symlink(os.path.abspath(t2_path), self.link_path) os.symlink('broken', broken_link_path, True) - self.sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) + os.symlink(join('tmp3', 'broken'), broken_link2_path, True) + os.symlink(join('SUB21', 'tmp5'), broken_link3_path, True) + self.sub2_tree = (sub2_path, ["link", "SUB21"], + ["broken_link", "broken_link2", "broken_link3", + "tmp3"]) else: self.sub2_tree = (sub2_path, [], ["tmp3"]) + os.chmod(sub21_path, 0) + self.addCleanup(os.chmod, sub21_path, stat.S_IRWXU) + def test_walk_topdown(self): # Walk top-down. all = list(self.walk(self.walk_path)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). +- Issue #28353: os.fwalk() no longer fails on broken links. + - Issue #28183: Optimize and cleanup dict iteration. - Issue #26081: Added C implementation of asyncio.Future. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 07:48:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 11:48:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIwNDkx?= =?utf-8?q?=3A_The_textwrap=2ETextWrapper_class_now_honors_non-breaking_sp?= =?utf-8?q?aces=2E?= Message-ID: <20161025114807.9814.65765.9E3015B1@psf.io> https://hg.python.org/cpython/rev/fcabef0ce773 changeset: 104708:fcabef0ce773 branch: 3.5 parent: 104705:fe1fea4ded04 user: Serhiy Storchaka date: Tue Oct 25 14:44:54 2016 +0300 summary: Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. Based on patch by Kaarle Ritvanen. files: Lib/test/test_textwrap.py | 31 +++++++++++++++++++++++++++ Lib/textwrap.py | 27 +++++++++++------------ Misc/NEWS | 3 ++ 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -444,6 +444,37 @@ text = "aa \xe4\xe4-\xe4\xe4" self.check_wrap(text, 7, ["aa \xe4\xe4-", "\xe4\xe4"]) + def test_non_breaking_space(self): + text = 'This is a sentence with non-breaking\N{NO-BREAK SPACE}space.' + + self.check_wrap(text, 20, + ['This is a sentence', + 'with non-', + 'breaking\N{NO-BREAK SPACE}space.'], + break_on_hyphens=True) + + self.check_wrap(text, 20, + ['This is a sentence', + 'with', + 'non-breaking\N{NO-BREAK SPACE}space.'], + break_on_hyphens=False) + + def test_narrow_non_breaking_space(self): + text = ('This is a sentence with non-breaking' + '\N{NARROW NO-BREAK SPACE}space.') + + self.check_wrap(text, 20, + ['This is a sentence', + 'with non-', + 'breaking\N{NARROW NO-BREAK SPACE}space.'], + break_on_hyphens=True) + + self.check_wrap(text, 20, + ['This is a sentence', + 'with', + 'non-breaking\N{NARROW NO-BREAK SPACE}space.'], + break_on_hyphens=False) + class MaxLinesTestCase(BaseTestCase): text = "Hello there, how are you this fine day? I'm glad to hear it!" diff --git a/Lib/textwrap.py b/Lib/textwrap.py --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -10,13 +10,8 @@ __all__ = ['TextWrapper', 'wrap', 'fill', 'dedent', 'indent', 'shorten'] # Hardcode the recognized whitespace characters to the US-ASCII -# whitespace characters. The main reason for doing this is that in -# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales -# that character winds up in string.whitespace. Respecting -# string.whitespace in those cases would 1) make textwrap treat 0xa0 the -# same as any other whitespace char, which is clearly wrong (it's a -# *non-breaking* space), 2) possibly cause problems with Unicode, -# since 0xa0 is not in range(128). +# whitespace characters. The main reason for doing this is that +# some Unicode spaces (like \u00a0) are non-breaking whitespaces. _whitespace = '\t\n\x0b\x0c\r ' class TextWrapper: @@ -81,29 +76,34 @@ # (after stripping out empty strings). word_punct = r'[\w!"\'&.,?]' letter = r'[^\d\W]' + whitespace = r'[%s]' % re.escape(_whitespace) + nowhitespace = '[^' + whitespace[1:] wordsep_re = re.compile(r''' ( # any whitespace - \s+ + %(ws)s+ | # em-dash between words (?<=%(wp)s) -{2,} (?=\w) | # word, possibly hyphenated - \S+? (?: + %(nws)s+? (?: # hyphenated word -(?: (?<=%(lt)s{2}-) | (?<=%(lt)s-%(lt)s-)) (?= %(lt)s -? %(lt)s) | # end of word - (?=\s|\Z) + (?=%(ws)s|\Z) | # em-dash (?<=%(wp)s) (?=-{2,}\w) ) - )''' % {'wp': word_punct, 'lt': letter}, re.VERBOSE) - del word_punct, letter + )''' % {'wp': word_punct, 'lt': letter, + 'ws': whitespace, 'nws': nowhitespace}, + re.VERBOSE) + del word_punct, letter, nowhitespace # This less funky little regex just split on recognized spaces. E.g. # "Hello there -- you goof-ball, use the -b option!" # splits into # Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ - wordsep_simple_re = re.compile(r'(\s+)') + wordsep_simple_re = re.compile(r'(%s+)' % whitespace) + del whitespace # XXX this is not locale- or charset-aware -- string.lowercase # is US-ASCII only (and therefore English-only) @@ -112,7 +112,6 @@ r'[\"\']?' # optional end-of-quote r'\Z') # end of chunk - def __init__(self, width=70, initial_indent="", diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. + Based on patch by Kaarle Ritvanen. + - Issue #28353: os.fwalk() no longer fails on broken links. - Issue #25464: Fixed HList.header_exists() in tkinter.tix module by addin -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 07:48:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 11:48:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2320491=3A_The_textwrap=2ETextWrapper_class_now_honors_?= =?utf-8?q?non-breaking_spaces=2E?= Message-ID: <20161025114808.18070.61144.EC2ED9C6@psf.io> https://hg.python.org/cpython/rev/bfa400108fc5 changeset: 104709:bfa400108fc5 branch: 3.6 parent: 104706:e99ec3c77a63 parent: 104708:fcabef0ce773 user: Serhiy Storchaka date: Tue Oct 25 14:46:44 2016 +0300 summary: Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. Based on patch by Kaarle Ritvanen. files: Lib/test/test_textwrap.py | 31 +++++++++++++++++++++++++++ Lib/textwrap.py | 27 +++++++++++------------ Misc/NEWS | 3 ++ 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -444,6 +444,37 @@ text = "aa \xe4\xe4-\xe4\xe4" self.check_wrap(text, 7, ["aa \xe4\xe4-", "\xe4\xe4"]) + def test_non_breaking_space(self): + text = 'This is a sentence with non-breaking\N{NO-BREAK SPACE}space.' + + self.check_wrap(text, 20, + ['This is a sentence', + 'with non-', + 'breaking\N{NO-BREAK SPACE}space.'], + break_on_hyphens=True) + + self.check_wrap(text, 20, + ['This is a sentence', + 'with', + 'non-breaking\N{NO-BREAK SPACE}space.'], + break_on_hyphens=False) + + def test_narrow_non_breaking_space(self): + text = ('This is a sentence with non-breaking' + '\N{NARROW NO-BREAK SPACE}space.') + + self.check_wrap(text, 20, + ['This is a sentence', + 'with non-', + 'breaking\N{NARROW NO-BREAK SPACE}space.'], + break_on_hyphens=True) + + self.check_wrap(text, 20, + ['This is a sentence', + 'with', + 'non-breaking\N{NARROW NO-BREAK SPACE}space.'], + break_on_hyphens=False) + class MaxLinesTestCase(BaseTestCase): text = "Hello there, how are you this fine day? I'm glad to hear it!" diff --git a/Lib/textwrap.py b/Lib/textwrap.py --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -10,13 +10,8 @@ __all__ = ['TextWrapper', 'wrap', 'fill', 'dedent', 'indent', 'shorten'] # Hardcode the recognized whitespace characters to the US-ASCII -# whitespace characters. The main reason for doing this is that in -# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales -# that character winds up in string.whitespace. Respecting -# string.whitespace in those cases would 1) make textwrap treat 0xa0 the -# same as any other whitespace char, which is clearly wrong (it's a -# *non-breaking* space), 2) possibly cause problems with Unicode, -# since 0xa0 is not in range(128). +# whitespace characters. The main reason for doing this is that +# some Unicode spaces (like \u00a0) are non-breaking whitespaces. _whitespace = '\t\n\x0b\x0c\r ' class TextWrapper: @@ -81,29 +76,34 @@ # (after stripping out empty strings). word_punct = r'[\w!"\'&.,?]' letter = r'[^\d\W]' + whitespace = r'[%s]' % re.escape(_whitespace) + nowhitespace = '[^' + whitespace[1:] wordsep_re = re.compile(r''' ( # any whitespace - \s+ + %(ws)s+ | # em-dash between words (?<=%(wp)s) -{2,} (?=\w) | # word, possibly hyphenated - \S+? (?: + %(nws)s+? (?: # hyphenated word -(?: (?<=%(lt)s{2}-) | (?<=%(lt)s-%(lt)s-)) (?= %(lt)s -? %(lt)s) | # end of word - (?=\s|\Z) + (?=%(ws)s|\Z) | # em-dash (?<=%(wp)s) (?=-{2,}\w) ) - )''' % {'wp': word_punct, 'lt': letter}, re.VERBOSE) - del word_punct, letter + )''' % {'wp': word_punct, 'lt': letter, + 'ws': whitespace, 'nws': nowhitespace}, + re.VERBOSE) + del word_punct, letter, nowhitespace # This less funky little regex just split on recognized spaces. E.g. # "Hello there -- you goof-ball, use the -b option!" # splits into # Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ - wordsep_simple_re = re.compile(r'(\s+)') + wordsep_simple_re = re.compile(r'(%s+)' % whitespace) + del whitespace # XXX this is not locale- or charset-aware -- string.lowercase # is US-ASCII only (and therefore English-only) @@ -112,7 +112,6 @@ r'[\"\']?' # optional end-of-quote r'\Z') # end of chunk - def __init__(self, width=70, initial_indent="", diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,9 @@ Library ------- +- Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. + Based on patch by Kaarle Ritvanen. + - Issue #28353: os.fwalk() no longer fails on broken links. - Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 07:48:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 11:48:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320491=3A_The_textwrap=2ETextWrapper_class_now_h?= =?utf-8?q?onors_non-breaking_spaces=2E?= Message-ID: <20161025114808.12034.13713.90618FD9@psf.io> https://hg.python.org/cpython/rev/b86dacb9e668 changeset: 104710:b86dacb9e668 parent: 104707:33a1a3dd0051 parent: 104709:bfa400108fc5 user: Serhiy Storchaka date: Tue Oct 25 14:47:53 2016 +0300 summary: Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. Based on patch by Kaarle Ritvanen. files: Lib/test/test_textwrap.py | 31 +++++++++++++++++++++++++++ Lib/textwrap.py | 27 +++++++++++------------ Misc/NEWS | 7 ++++- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -444,6 +444,37 @@ text = "aa \xe4\xe4-\xe4\xe4" self.check_wrap(text, 7, ["aa \xe4\xe4-", "\xe4\xe4"]) + def test_non_breaking_space(self): + text = 'This is a sentence with non-breaking\N{NO-BREAK SPACE}space.' + + self.check_wrap(text, 20, + ['This is a sentence', + 'with non-', + 'breaking\N{NO-BREAK SPACE}space.'], + break_on_hyphens=True) + + self.check_wrap(text, 20, + ['This is a sentence', + 'with', + 'non-breaking\N{NO-BREAK SPACE}space.'], + break_on_hyphens=False) + + def test_narrow_non_breaking_space(self): + text = ('This is a sentence with non-breaking' + '\N{NARROW NO-BREAK SPACE}space.') + + self.check_wrap(text, 20, + ['This is a sentence', + 'with non-', + 'breaking\N{NARROW NO-BREAK SPACE}space.'], + break_on_hyphens=True) + + self.check_wrap(text, 20, + ['This is a sentence', + 'with', + 'non-breaking\N{NARROW NO-BREAK SPACE}space.'], + break_on_hyphens=False) + class MaxLinesTestCase(BaseTestCase): text = "Hello there, how are you this fine day? I'm glad to hear it!" diff --git a/Lib/textwrap.py b/Lib/textwrap.py --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -10,13 +10,8 @@ __all__ = ['TextWrapper', 'wrap', 'fill', 'dedent', 'indent', 'shorten'] # Hardcode the recognized whitespace characters to the US-ASCII -# whitespace characters. The main reason for doing this is that in -# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales -# that character winds up in string.whitespace. Respecting -# string.whitespace in those cases would 1) make textwrap treat 0xa0 the -# same as any other whitespace char, which is clearly wrong (it's a -# *non-breaking* space), 2) possibly cause problems with Unicode, -# since 0xa0 is not in range(128). +# whitespace characters. The main reason for doing this is that +# some Unicode spaces (like \u00a0) are non-breaking whitespaces. _whitespace = '\t\n\x0b\x0c\r ' class TextWrapper: @@ -81,29 +76,34 @@ # (after stripping out empty strings). word_punct = r'[\w!"\'&.,?]' letter = r'[^\d\W]' + whitespace = r'[%s]' % re.escape(_whitespace) + nowhitespace = '[^' + whitespace[1:] wordsep_re = re.compile(r''' ( # any whitespace - \s+ + %(ws)s+ | # em-dash between words (?<=%(wp)s) -{2,} (?=\w) | # word, possibly hyphenated - \S+? (?: + %(nws)s+? (?: # hyphenated word -(?: (?<=%(lt)s{2}-) | (?<=%(lt)s-%(lt)s-)) (?= %(lt)s -? %(lt)s) | # end of word - (?=\s|\Z) + (?=%(ws)s|\Z) | # em-dash (?<=%(wp)s) (?=-{2,}\w) ) - )''' % {'wp': word_punct, 'lt': letter}, re.VERBOSE) - del word_punct, letter + )''' % {'wp': word_punct, 'lt': letter, + 'ws': whitespace, 'nws': nowhitespace}, + re.VERBOSE) + del word_punct, letter, nowhitespace # This less funky little regex just split on recognized spaces. E.g. # "Hello there -- you goof-ball, use the -b option!" # splits into # Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ - wordsep_simple_re = re.compile(r'(\s+)') + wordsep_simple_re = re.compile(r'(%s+)' % whitespace) + del whitespace # XXX this is not locale- or charset-aware -- string.lowercase # is US-ASCII only (and therefore English-only) @@ -112,7 +112,6 @@ r'[\"\']?' # optional end-of-quote r'\Z') # end of chunk - def __init__(self, width=70, initial_indent="", diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,8 +22,6 @@ - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception loss in PyTraceBack_Here(). -- Issue #28353: os.fwalk() no longer fails on broken links. - - Issue #28183: Optimize and cleanup dict iteration. - Issue #26081: Added C implementation of asyncio.Future. @@ -99,6 +97,11 @@ Library ------- +- Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. + Based on patch by Kaarle Ritvanen. + +- Issue #28353: os.fwalk() no longer fails on broken links. + - Issue #28430: Fix iterator of C implemented asyncio.Future doesn't accept non-None value is passed to it.send(val). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:04:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:04:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MjU1?= =?utf-8?q?=3A_calendar=2ETextCalendar=28=29=2Eprmonth=28=29_no_longer_pri?= =?utf-8?q?nts_a_space?= Message-ID: <20161025120427.25214.27201.62CBAC17@psf.io> https://hg.python.org/cpython/rev/8d54c2a1c796 changeset: 104711:8d54c2a1c796 branch: 3.5 parent: 104708:fcabef0ce773 user: Serhiy Storchaka date: Tue Oct 25 15:00:52 2016 +0300 summary: Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. files: Lib/calendar.py | 2 +- Lib/test/test_calendar.py | 3 +-- Misc/NEWS | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/calendar.py b/Lib/calendar.py --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -312,7 +312,7 @@ """ Print a month's calendar. """ - print(self.formatmonth(theyear, themonth, w, l), end=' ') + print(self.formatmonth(theyear, themonth, w, l), end='') def formatmonth(self, theyear, themonth, w=0, l=0): """ diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -409,8 +409,7 @@ def test_prmonth(self): with support.captured_stdout() as out: calendar.TextCalendar().prmonth(2004, 1) - output = out.getvalue().strip() - self.assertEqual(output, result_2004_01_text.strip()) + self.assertEqual(out.getvalue(), result_2004_01_text) def test_pryear(self): with support.captured_stdout() as out: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,10 @@ Library ------- +- Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space + at the start of new line after printing a month's calendar. Patch by + Xiang Zhang. + - Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. Based on patch by Kaarle Ritvanen. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:04:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:04:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328255=3A_calendar=2ETextCalendar=28=29=2Eprmont?= =?utf-8?q?h=28=29_no_longer_prints_a_space?= Message-ID: <20161025120428.27644.88010.97EA872C@psf.io> https://hg.python.org/cpython/rev/049e58f74272 changeset: 104713:049e58f74272 parent: 104710:b86dacb9e668 parent: 104712:ebe5bd33f86f user: Serhiy Storchaka date: Tue Oct 25 15:03:59 2016 +0300 summary: Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. files: Lib/calendar.py | 2 +- Lib/test/test_calendar.py | 3 +-- Misc/NEWS | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/calendar.py b/Lib/calendar.py --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -314,7 +314,7 @@ """ Print a month's calendar. """ - print(self.formatmonth(theyear, themonth, w, l), end=' ') + print(self.formatmonth(theyear, themonth, w, l), end='') def formatmonth(self, theyear, themonth, w=0, l=0): """ diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -409,8 +409,7 @@ def test_prmonth(self): with support.captured_stdout() as out: calendar.TextCalendar().prmonth(2004, 1) - output = out.getvalue().strip() - self.assertEqual(output, result_2004_01_text.strip()) + self.assertEqual(out.getvalue(), result_2004_01_text) def test_pryear(self): with support.captured_stdout() as out: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,10 @@ Library ------- +- Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space + at the start of new line after printing a month's calendar. Patch by + Xiang Zhang. + - Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. Based on patch by Kaarle Ritvanen. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:04:28 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:04:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328255=3A_calendar=2ETextCalendar=28=29=2Eprmonth=28?= =?utf-8?q?=29_no_longer_prints_a_space?= Message-ID: <20161025120428.38687.468.7031DA04@psf.io> https://hg.python.org/cpython/rev/ebe5bd33f86f changeset: 104712:ebe5bd33f86f branch: 3.6 parent: 104709:bfa400108fc5 parent: 104711:8d54c2a1c796 user: Serhiy Storchaka date: Tue Oct 25 15:02:36 2016 +0300 summary: Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. files: Lib/calendar.py | 2 +- Lib/test/test_calendar.py | 3 +-- Misc/NEWS | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/calendar.py b/Lib/calendar.py --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -314,7 +314,7 @@ """ Print a month's calendar. """ - print(self.formatmonth(theyear, themonth, w, l), end=' ') + print(self.formatmonth(theyear, themonth, w, l), end='') def formatmonth(self, theyear, themonth, w=0, l=0): """ diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -409,8 +409,7 @@ def test_prmonth(self): with support.captured_stdout() as out: calendar.TextCalendar().prmonth(2004, 1) - output = out.getvalue().strip() - self.assertEqual(output, result_2004_01_text.strip()) + self.assertEqual(out.getvalue(), result_2004_01_text) def test_pryear(self): with support.captured_stdout() as out: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,10 @@ Library ------- +- Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space + at the start of new line after printing a month's calendar. Patch by + Xiang Zhang. + - Issue #20491: The textwrap.TextWrapper class now honors non-breaking spaces. Based on patch by Kaarle Ritvanen. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:21:18 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:21:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2328255=3A_calendar?= =?utf-8?q?=2ETextCalendar=2Eprweek=28=29_no_longer_prints_a_space_after?= Message-ID: <20161025122117.16797.57302.9740F488@psf.io> https://hg.python.org/cpython/rev/4a3892f49e1a changeset: 104714:4a3892f49e1a user: Serhiy Storchaka date: Tue Oct 25 15:20:58 2016 +0300 summary: Issue #28255: calendar.TextCalendar.prweek() no longer prints a space after a weeks's calendar. calendar.TextCalendar.pryear() no longer prints redundant newline after a year's calendar. Based on patch by Xiang Zhang. files: Lib/calendar.py | 4 ++-- Lib/test/test_calendar.py | 4 ++-- Misc/NEWS | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/calendar.py b/Lib/calendar.py --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -267,7 +267,7 @@ """ Print a single week (no newline). """ - print(self.formatweek(theweek, width), end=' ') + print(self.formatweek(theweek, width), end='') def formatday(self, day, weekday, width): """ @@ -371,7 +371,7 @@ def pryear(self, theyear, w=0, l=0, c=6, m=3): """Print a year's calendar.""" - print(self.formatyear(theyear, w, l, c, m)) + print(self.formatyear(theyear, w, l, c, m), end='') class HTMLCalendar(Calendar): diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -404,7 +404,7 @@ with support.captured_stdout() as out: week = [(1,0), (2,1), (3,2), (4,3), (5,4), (6,5), (7,6)] calendar.TextCalendar().prweek(week, 1) - self.assertEqual(out.getvalue().strip(), "1 2 3 4 5 6 7") + self.assertEqual(out.getvalue(), " 1 2 3 4 5 6 7") def test_prmonth(self): with support.captured_stdout() as out: @@ -414,7 +414,7 @@ def test_pryear(self): with support.captured_stdout() as out: calendar.TextCalendar().pryear(2004) - self.assertEqual(out.getvalue().strip(), result_2004_text.strip()) + self.assertEqual(out.getvalue(), result_2004_text) def test_format(self): with support.captured_stdout() as out: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,7 +97,11 @@ Library ------- -- Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space +- Issue #28255: calendar.TextCalendar.prweek() no longer prints a space after + a weeks's calendar. calendar.TextCalendar.pryear() no longer prints redundant + newline after a year's calendar. Based on patch by Xiang Zhang. + +- Issue #28255: calendar.TextCalendar.prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:38:47 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:38:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3Mjc1?= =?utf-8?q?=3A_Fixed_implementation_of_pop=28=29_and_popitem=28=29_methods?= =?utf-8?q?_in?= Message-ID: <20161025123847.110788.61372.4B98A5B6@psf.io> https://hg.python.org/cpython/rev/9f7505019767 changeset: 104715:9f7505019767 branch: 3.5 parent: 104711:8d54c2a1c796 user: Serhiy Storchaka date: Tue Oct 25 15:33:23 2016 +0300 summary: Issue #27275: Fixed implementation of pop() and popitem() methods in subclasses of accelerated OrderedDict. files: Lib/test/test_ordered_dict.py | 59 +++++++++++++++++++++++ Misc/NEWS | 3 + Objects/odictobject.c | 29 ++-------- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -730,5 +730,64 @@ self.assertRaises(KeyError, d.popitem) +class SimpleLRUCache: + + def __init__(self, size): + super().__init__() + self.size = size + + def __getitem__(self, item): + value = super().__getitem__(item) + self.move_to_end(item) + return value + + def __setitem__(self, key, value): + while key not in self and len(self) >= self.size: + self.popitem(last=False) + super().__setitem__(key, value) + self.move_to_end(key) + + +class SimpleLRUCacheTests: + + def test_add_after_full(self): + c = self.type2test(2) + c['t1'] = 1 + c['t2'] = 2 + c['t3'] = 3 + self.assertEqual(list(c), ['t2', 't3']) + + def test_popitem(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(c.popitem(last=False), (1, 1)) + self.assertEqual(c.popitem(last=True), (3, 3)) + + def test_change_order_on_get(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(list(c), list(range(1, 4))) + self.assertEqual(c[2], 2) + self.assertEqual(list(c), [1, 3, 2]) + + +class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + class type2test(SimpleLRUCache, py_coll.OrderedDict): + pass + + + at unittest.skipUnless(c_coll, 'requires the C version of the collections module') +class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + @classmethod + def setUpClass(cls): + class type2test(SimpleLRUCache, c_coll.OrderedDict): + pass + cls.type2test = type2test + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #27275: Fixed implementation of pop() and popitem() methods in + subclasses of accelerated OrderedDict. + - Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1099,28 +1099,13 @@ } /* Now delete the value from the dict. */ - if (PyODict_CheckExact(od)) { - if (node != NULL) { - value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ - if (value != NULL) { - Py_INCREF(value); - if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { - Py_DECREF(value); - return NULL; - } - } - } - } - else { - int exists = PySequence_Contains(od, key); - if (exists < 0) - return NULL; - if (exists) { - value = PyObject_GetItem(od, key); - if (value != NULL) { - if (PyObject_DelItem(od, key) == -1) { - Py_CLEAR(value); - } + if (node != NULL) { + value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ + if (value != NULL) { + Py_INCREF(value); + if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { + Py_DECREF(value); + return NULL; } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:38:53 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:38:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2327275=3A_Fixed_implementation_of_pop=28=29_and_popite?= =?utf-8?q?m=28=29_methods_in?= Message-ID: <20161025123847.27413.18779.541D53BC@psf.io> https://hg.python.org/cpython/rev/2def8a24c299 changeset: 104716:2def8a24c299 branch: 3.6 parent: 104712:ebe5bd33f86f parent: 104715:9f7505019767 user: Serhiy Storchaka date: Tue Oct 25 15:36:56 2016 +0300 summary: Issue #27275: Fixed implementation of pop() and popitem() methods in subclasses of accelerated OrderedDict. files: Lib/test/test_ordered_dict.py | 59 +++++++++++++++++++++++ Misc/NEWS | 3 + Objects/odictobject.c | 29 ++-------- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -775,5 +775,64 @@ self.assertRaises(KeyError, d.popitem) +class SimpleLRUCache: + + def __init__(self, size): + super().__init__() + self.size = size + + def __getitem__(self, item): + value = super().__getitem__(item) + self.move_to_end(item) + return value + + def __setitem__(self, key, value): + while key not in self and len(self) >= self.size: + self.popitem(last=False) + super().__setitem__(key, value) + self.move_to_end(key) + + +class SimpleLRUCacheTests: + + def test_add_after_full(self): + c = self.type2test(2) + c['t1'] = 1 + c['t2'] = 2 + c['t3'] = 3 + self.assertEqual(list(c), ['t2', 't3']) + + def test_popitem(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(c.popitem(last=False), (1, 1)) + self.assertEqual(c.popitem(last=True), (3, 3)) + + def test_change_order_on_get(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(list(c), list(range(1, 4))) + self.assertEqual(c[2], 2) + self.assertEqual(list(c), [1, 3, 2]) + + +class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + class type2test(SimpleLRUCache, py_coll.OrderedDict): + pass + + + at unittest.skipUnless(c_coll, 'requires the C version of the collections module') +class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + @classmethod + def setUpClass(cls): + class type2test(SimpleLRUCache, c_coll.OrderedDict): + pass + cls.type2test = type2test + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,9 @@ Library ------- +- Issue #27275: Fixed implementation of pop() and popitem() methods in + subclasses of accelerated OrderedDict. + - Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1102,28 +1102,13 @@ } /* Now delete the value from the dict. */ - if (PyODict_CheckExact(od)) { - if (node != NULL) { - value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ - if (value != NULL) { - Py_INCREF(value); - if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { - Py_DECREF(value); - return NULL; - } - } - } - } - else { - int exists = PySequence_Contains(od, key); - if (exists < 0) - return NULL; - if (exists) { - value = PyObject_GetItem(od, key); - if (value != NULL) { - if (PyObject_DelItem(od, key) == -1) { - Py_CLEAR(value); - } + if (node != NULL) { + value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ + if (value != NULL) { + Py_INCREF(value); + if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { + Py_DECREF(value); + return NULL; } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 08:38:53 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 12:38:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327275=3A_Fixed_implementation_of_pop=28=29_and_?= =?utf-8?q?popitem=28=29_methods_in?= Message-ID: <20161025123847.18098.5137.2609D1AF@psf.io> https://hg.python.org/cpython/rev/19e199038704 changeset: 104717:19e199038704 parent: 104714:4a3892f49e1a parent: 104716:2def8a24c299 user: Serhiy Storchaka date: Tue Oct 25 15:38:28 2016 +0300 summary: Issue #27275: Fixed implementation of pop() and popitem() methods in subclasses of accelerated OrderedDict. files: Lib/test/test_ordered_dict.py | 59 +++++++++++++++++++++++ Misc/NEWS | 3 + Objects/odictobject.c | 29 ++-------- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -775,5 +775,64 @@ self.assertRaises(KeyError, d.popitem) +class SimpleLRUCache: + + def __init__(self, size): + super().__init__() + self.size = size + + def __getitem__(self, item): + value = super().__getitem__(item) + self.move_to_end(item) + return value + + def __setitem__(self, key, value): + while key not in self and len(self) >= self.size: + self.popitem(last=False) + super().__setitem__(key, value) + self.move_to_end(key) + + +class SimpleLRUCacheTests: + + def test_add_after_full(self): + c = self.type2test(2) + c['t1'] = 1 + c['t2'] = 2 + c['t3'] = 3 + self.assertEqual(list(c), ['t2', 't3']) + + def test_popitem(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(c.popitem(last=False), (1, 1)) + self.assertEqual(c.popitem(last=True), (3, 3)) + + def test_change_order_on_get(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(list(c), list(range(1, 4))) + self.assertEqual(c[2], 2) + self.assertEqual(list(c), [1, 3, 2]) + + +class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + class type2test(SimpleLRUCache, py_coll.OrderedDict): + pass + + + at unittest.skipUnless(c_coll, 'requires the C version of the collections module') +class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + @classmethod + def setUpClass(cls): + class type2test(SimpleLRUCache, c_coll.OrderedDict): + pass + cls.type2test = type2test + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ Library ------- +- Issue #27275: Fixed implementation of pop() and popitem() methods in + subclasses of accelerated OrderedDict. + - Issue #28255: calendar.TextCalendar.prweek() no longer prints a space after a weeks's calendar. calendar.TextCalendar.pryear() no longer prints redundant newline after a year's calendar. Based on patch by Xiang Zhang. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1102,28 +1102,13 @@ } /* Now delete the value from the dict. */ - if (PyODict_CheckExact(od)) { - if (node != NULL) { - value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ - if (value != NULL) { - Py_INCREF(value); - if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { - Py_DECREF(value); - return NULL; - } - } - } - } - else { - int exists = PySequence_Contains(od, key); - if (exists < 0) - return NULL; - if (exists) { - value = PyObject_GetItem(od, key); - if (value != NULL) { - if (PyObject_DelItem(od, key) == -1) { - Py_CLEAR(value); - } + if (node != NULL) { + value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ + if (value != NULL) { + Py_INCREF(value); + if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { + Py_DECREF(value); + return NULL; } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 11:49:54 2016 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Oct 2016 15:49:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgMjUwMDI6?= =?utf-8?q?_Deprecate_asyncore/asynchat=2E_Patch_by_Mariatta=2E?= Message-ID: <20161025154953.110892.20339.E31DB1E6@psf.io> https://hg.python.org/cpython/rev/bb23770f82f1 changeset: 104718:bb23770f82f1 branch: 3.6 parent: 104716:2def8a24c299 user: Guido van Rossum date: Tue Oct 25 08:49:13 2016 -0700 summary: Issue 25002: Deprecate asyncore/asynchat. Patch by Mariatta. files: Doc/library/asynchat.rst | 3 +++ Doc/library/asyncore.rst | 3 +++ Lib/asynchat.py | 5 +++++ Lib/asyncore.py | 4 ++++ 4 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Doc/library/asynchat.rst b/Doc/library/asynchat.rst --- a/Doc/library/asynchat.rst +++ b/Doc/library/asynchat.rst @@ -9,6 +9,9 @@ **Source code:** :source:`Lib/asynchat.py` +.. deprecated:: 3.6 + Please use :mod:`asyncio` instead. + -------------- .. note:: diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -12,6 +12,9 @@ **Source code:** :source:`Lib/asyncore.py` +.. deprecated:: 3.6 + Please use :mod:`asyncio` instead. + -------------- .. note:: diff --git a/Lib/asynchat.py b/Lib/asynchat.py --- a/Lib/asynchat.py +++ b/Lib/asynchat.py @@ -46,8 +46,13 @@ you - by calling your self.found_terminator() method. """ import asyncore +import warnings + from collections import deque +warnings.warn( + 'asynchat module is deprecated in 3.6. Use asyncio instead.', + PendingDeprecationWarning, stacklevel=2) class async_chat(asyncore.dispatcher): """This is an abstract class. You must derive from this class, and add diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -60,6 +60,10 @@ _DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF}) +warnings.warn( + 'asyncore module is deprecated in 3.6. Use asyncio instead.', + PendingDeprecationWarning, stacklevel=2) + try: socket_map except NameError: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 11:50:03 2016 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Oct 2016 15:50:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_25002=3A_Deprecate_asyncore/asynchat=2E_Patch_by_M?= =?utf-8?b?YXJpYXR0YS4gKDMuNi0+My43KQ==?= Message-ID: <20161025154953.9757.19153.F97E4373@psf.io> https://hg.python.org/cpython/rev/3b8dfe6f5bcb changeset: 104719:3b8dfe6f5bcb parent: 104717:19e199038704 parent: 104718:bb23770f82f1 user: Guido van Rossum date: Tue Oct 25 08:49:48 2016 -0700 summary: Issue 25002: Deprecate asyncore/asynchat. Patch by Mariatta. (3.6->3.7) files: Doc/library/asynchat.rst | 3 +++ Doc/library/asyncore.rst | 3 +++ Lib/asynchat.py | 5 +++++ Lib/asyncore.py | 4 ++++ 4 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Doc/library/asynchat.rst b/Doc/library/asynchat.rst --- a/Doc/library/asynchat.rst +++ b/Doc/library/asynchat.rst @@ -9,6 +9,9 @@ **Source code:** :source:`Lib/asynchat.py` +.. deprecated:: 3.6 + Please use :mod:`asyncio` instead. + -------------- .. note:: diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -12,6 +12,9 @@ **Source code:** :source:`Lib/asyncore.py` +.. deprecated:: 3.6 + Please use :mod:`asyncio` instead. + -------------- .. note:: diff --git a/Lib/asynchat.py b/Lib/asynchat.py --- a/Lib/asynchat.py +++ b/Lib/asynchat.py @@ -46,8 +46,13 @@ you - by calling your self.found_terminator() method. """ import asyncore +import warnings + from collections import deque +warnings.warn( + 'asynchat module is deprecated in 3.6. Use asyncio instead.', + PendingDeprecationWarning, stacklevel=2) class async_chat(asyncore.dispatcher): """This is an abstract class. You must derive from this class, and add diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -60,6 +60,10 @@ _DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF}) +warnings.warn( + 'asyncore module is deprecated in 3.6. Use asyncio instead.', + PendingDeprecationWarning, stacklevel=2) + try: socket_map except NameError: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 12:03:41 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 16:03:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzUz?= =?utf-8?q?=3A_Try_to_fix_tests=2E?= Message-ID: <20161025160338.110735.98822.97D122AA@psf.io> https://hg.python.org/cpython/rev/ec12e16ea6a1 changeset: 104720:ec12e16ea6a1 branch: 3.6 parent: 104718:bb23770f82f1 user: Serhiy Storchaka date: Tue Oct 25 19:01:41 2016 +0300 summary: Issue #28353: Try to fix tests. files: Lib/test/test_os.py | 15 +++++++++++++-- 1 files changed, 13 insertions(+), 2 deletions(-) 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 @@ -892,14 +892,22 @@ os.symlink('broken', broken_link_path, True) os.symlink(join('tmp3', 'broken'), broken_link2_path, True) os.symlink(join('SUB21', 'tmp5'), broken_link3_path, True) - self.sub2_tree = (sub2_path, ["link", "SUB21"], + self.sub2_tree = (sub2_path, ["SUB21", "link"], ["broken_link", "broken_link2", "broken_link3", "tmp3"]) else: self.sub2_tree = (sub2_path, [], ["tmp3"]) os.chmod(sub21_path, 0) - self.addCleanup(os.chmod, sub21_path, stat.S_IRWXU) + try: + os.listdir(sub21_path) + except PermissionError: + self.addCleanup(os.chmod, sub21_path, stat.S_IRWXU) + else: + os.chmod(sub21_path, stat.S_IRWXU) + os.unlink(tmp5_path) + os.rmdir(sub21_path) + del self.sub2_tree[1][:1] def test_walk_topdown(self): # Walk top-down. @@ -912,6 +920,7 @@ flipped = all[0][1][0] != "SUB1" all[0][1].sort() all[3 - 2 * flipped][-1].sort() + all[3 - 2 * flipped][1].sort() self.assertEqual(all[0], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[1 + flipped], (self.sub1_path, ["SUB11"], ["tmp2"])) self.assertEqual(all[2 + flipped], (self.sub11_path, [], [])) @@ -934,6 +943,7 @@ (str(walk_path), ["SUB2"], ["tmp1"])) all[1][-1].sort() + all[1][1].sort() self.assertEqual(all[1], self.sub2_tree) def test_file_like_path(self): @@ -950,6 +960,7 @@ flipped = all[3][1][0] != "SUB1" all[3][1].sort() all[2 - 2 * flipped][-1].sort() + all[2 - 2 * flipped][1].sort() self.assertEqual(all[3], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[flipped], -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 12:04:11 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 16:04:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328353=3A_Try_to_fix_tests=2E?= Message-ID: <20161025160339.25360.39726.B6FA89A2@psf.io> https://hg.python.org/cpython/rev/a0913dbadea6 changeset: 104721:a0913dbadea6 parent: 104719:3b8dfe6f5bcb parent: 104720:ec12e16ea6a1 user: Serhiy Storchaka date: Tue Oct 25 19:03:27 2016 +0300 summary: Issue #28353: Try to fix tests. files: Lib/test/test_os.py | 15 +++++++++++++-- 1 files changed, 13 insertions(+), 2 deletions(-) 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 @@ -892,14 +892,22 @@ os.symlink('broken', broken_link_path, True) os.symlink(join('tmp3', 'broken'), broken_link2_path, True) os.symlink(join('SUB21', 'tmp5'), broken_link3_path, True) - self.sub2_tree = (sub2_path, ["link", "SUB21"], + self.sub2_tree = (sub2_path, ["SUB21", "link"], ["broken_link", "broken_link2", "broken_link3", "tmp3"]) else: self.sub2_tree = (sub2_path, [], ["tmp3"]) os.chmod(sub21_path, 0) - self.addCleanup(os.chmod, sub21_path, stat.S_IRWXU) + try: + os.listdir(sub21_path) + except PermissionError: + self.addCleanup(os.chmod, sub21_path, stat.S_IRWXU) + else: + os.chmod(sub21_path, stat.S_IRWXU) + os.unlink(tmp5_path) + os.rmdir(sub21_path) + del self.sub2_tree[1][:1] def test_walk_topdown(self): # Walk top-down. @@ -912,6 +920,7 @@ flipped = all[0][1][0] != "SUB1" all[0][1].sort() all[3 - 2 * flipped][-1].sort() + all[3 - 2 * flipped][1].sort() self.assertEqual(all[0], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[1 + flipped], (self.sub1_path, ["SUB11"], ["tmp2"])) self.assertEqual(all[2 + flipped], (self.sub11_path, [], [])) @@ -934,6 +943,7 @@ (str(walk_path), ["SUB2"], ["tmp1"])) all[1][-1].sort() + all[1][1].sort() self.assertEqual(all[1], self.sub2_tree) def test_file_like_path(self): @@ -950,6 +960,7 @@ flipped = all[3][1][0] != "SUB1" all[3][1].sort() all[2 - 2 * flipped][-1].sort() + all[2 - 2 * flipped][1].sort() self.assertEqual(all[3], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[flipped], -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 12:54:31 2016 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Oct 2016 16:54:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MTA3?= =?utf-8?q?=3A_Update_typing_module_documentation_for_NamedTuple_=28Ivan?= =?utf-8?q?=29?= Message-ID: <20161025165422.18098.80320.A43709F6@psf.io> https://hg.python.org/cpython/rev/78c0487562d9 changeset: 104722:78c0487562d9 branch: 3.6 parent: 104720:ec12e16ea6a1 user: Guido van Rossum date: Tue Oct 25 09:53:11 2016 -0700 summary: Issue #28107: Update typing module documentation for NamedTuple (Ivan) files: Doc/library/typing.rst | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -677,23 +677,32 @@ ``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or ``Match[bytes]``. -.. function:: NamedTuple(typename, fields) +.. class:: NamedTuple Typed version of namedtuple. Usage:: - Employee = typing.NamedTuple('Employee', [('name', str), ('id', int)]) + class Employee(NamedTuple): + name: str + id: int This is equivalent to:: Employee = collections.namedtuple('Employee', ['name', 'id']) - The resulting class has one extra attribute: _field_types, + The resulting class has one extra attribute: ``_field_types``, giving a dict mapping field names to types. (The field names - are in the _fields attribute, which is part of the namedtuple + are in the ``_fields`` attribute, which is part of the namedtuple API.) + Backward-compatible usage:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + + .. versionchanged:: 3.6 + Added support for :pep:`526` variable annotation syntax. + .. function:: NewType(typ) A helper function to indicate a distinct types to a typechecker, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 12:54:31 2016 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Oct 2016 16:54:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328107=3A_Update_typing_module_documentation_for?= =?utf-8?q?_NamedTuple_=28Ivan=29?= Message-ID: <20161025165422.9679.5544.50D49157@psf.io> https://hg.python.org/cpython/rev/709b19b9d6ea changeset: 104723:709b19b9d6ea parent: 104721:a0913dbadea6 parent: 104722:78c0487562d9 user: Guido van Rossum date: Tue Oct 25 09:54:11 2016 -0700 summary: Issue #28107: Update typing module documentation for NamedTuple (Ivan) (3.6->3.7) files: Doc/library/typing.rst | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -677,23 +677,32 @@ ``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or ``Match[bytes]``. -.. function:: NamedTuple(typename, fields) +.. class:: NamedTuple Typed version of namedtuple. Usage:: - Employee = typing.NamedTuple('Employee', [('name', str), ('id', int)]) + class Employee(NamedTuple): + name: str + id: int This is equivalent to:: Employee = collections.namedtuple('Employee', ['name', 'id']) - The resulting class has one extra attribute: _field_types, + The resulting class has one extra attribute: ``_field_types``, giving a dict mapping field names to types. (The field names - are in the _fields attribute, which is part of the namedtuple + are in the ``_fields`` attribute, which is part of the namedtuple API.) + Backward-compatible usage:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + + .. versionchanged:: 3.6 + Added support for :pep:`526` variable annotation syntax. + .. function:: NewType(typ) A helper function to indicate a distinct types to a typechecker, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 13:20:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 17:20:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20161025172047.102197.68598.FC1D059E@psf.io> https://hg.python.org/cpython/rev/665171386c65 changeset: 104726:665171386c65 parent: 104723:709b19b9d6ea parent: 104725:84a3c5003510 user: Serhiy Storchaka date: Tue Oct 25 20:20:29 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 13:20:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 17:20:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzUz?= =?utf-8?q?=3A_Fixed_tests_of_os=2Efwalk=28=29_with_broken_links=2E?= Message-ID: <20161025172047.16715.33493.8FCCD1DB@psf.io> https://hg.python.org/cpython/rev/470224ec16b6 changeset: 104724:470224ec16b6 branch: 3.5 parent: 104715:9f7505019767 user: Serhiy Storchaka date: Tue Oct 25 20:18:31 2016 +0300 summary: Issue #28353: Fixed tests of os.fwalk() with broken links. files: Lib/test/test_os.py | 21 ++++++++++++++++++--- 1 files changed, 18 insertions(+), 3 deletions(-) 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 @@ -869,13 +869,23 @@ os.symlink('broken', broken_link_path, True) os.symlink(join('tmp3', 'broken'), broken_link2_path, True) os.symlink(join('SUB21', 'tmp5'), broken_link3_path, True) - self.sub2_tree = (sub2_path, ["link", "SUB21"], + self.sub2_tree = (sub2_path, ["SUB21", "link"], ["broken_link", "broken_link2", "broken_link3", "tmp3"]) else: self.sub2_tree = (sub2_path, [], ["tmp3"]) os.chmod(self.sub21_path, 0) + try: + os.listdir(self.sub21_path) + except PermissionError: + pass + else: + os.chmod(self.sub21_path, stat.S_IRWXU) + os.unlink(tmp5_path) + os.rmdir(self.sub21_path) + self.sub21_path = None + del self.sub2_tree[1][:1] def test_walk_topdown(self): # Walk top-down. @@ -888,6 +898,7 @@ flipped = all[0][1][0] != "SUB1" all[0][1].sort() all[3 - 2 * flipped][-1].sort() + all[3 - 2 * flipped][1].sort() self.assertEqual(all[0], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[1 + flipped], (self.sub1_path, ["SUB11"], ["tmp2"])) self.assertEqual(all[2 + flipped], (self.sub11_path, [], [])) @@ -908,6 +919,7 @@ (self.walk_path, ["SUB2"], ["tmp1"])) all[1][-1].sort() + all[1][1].sort() self.assertEqual(all[1], self.sub2_tree) def test_walk_bottom_up(self): @@ -921,6 +933,7 @@ flipped = all[3][1][0] != "SUB1" all[3][1].sort() all[2 - 2 * flipped][-1].sort() + all[2 - 2 * flipped][1].sort() self.assertEqual(all[3], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[flipped], @@ -949,7 +962,8 @@ # Windows, which doesn't have a recursive delete command. The # (not so) subtlety is that rmdir will fail unless the dir's # kids are removed first, so bottom up is essential. - os.chmod(self.sub21_path, stat.S_IRWXU) + if self.sub21_path: + os.chmod(self.sub21_path, stat.S_IRWXU) for root, dirs, files in os.walk(support.TESTFN, topdown=False): for name in files: os.remove(os.path.join(root, name)) @@ -1045,7 +1059,8 @@ def tearDown(self): # cleanup - os.chmod(self.sub21_path, stat.S_IRWXU) + if self.sub21_path: + os.chmod(self.sub21_path, stat.S_IRWXU) for root, dirs, files, rootfd in os.fwalk(support.TESTFN, topdown=False): for name in files: os.unlink(name, dir_fd=rootfd) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 13:20:59 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Oct 2016 17:20:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Null_merge?= Message-ID: <20161025172047.11965.96052.6CC0F15C@psf.io> https://hg.python.org/cpython/rev/84a3c5003510 changeset: 104725:84a3c5003510 branch: 3.6 parent: 104722:78c0487562d9 parent: 104724:470224ec16b6 user: Serhiy Storchaka date: Tue Oct 25 20:20:09 2016 +0300 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 14:52:43 2016 From: python-checkins at python.org (steve.dower) Date: Tue, 25 Oct 2016 18:52:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328333=3A_Fixes_off-by-one_error_that_was_adding?= =?utf-8?q?_an_extra_space=2E?= Message-ID: <20161025185229.25360.37606.AD9B91A1@psf.io> https://hg.python.org/cpython/rev/44d15ba67d2e changeset: 104728:44d15ba67d2e parent: 104726:665171386c65 parent: 104727:6b46c3deea2c user: Steve Dower date: Tue Oct 25 11:52:09 2016 -0700 summary: Issue #28333: Fixes off-by-one error that was adding an extra space. files: Parser/myreadline.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -225,7 +225,8 @@ if (wlen) { DWORD n; fflush(stderr); - WriteConsoleW(hStdErr, wbuf, wlen, &n, NULL); + /* wlen includes null terminator, so subtract 1 */ + WriteConsoleW(hStdErr, wbuf, wlen - 1, &n, NULL); } PyMem_RawFree(wbuf); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 14:52:43 2016 From: python-checkins at python.org (steve.dower) Date: Tue, 25 Oct 2016 18:52:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MzMz?= =?utf-8?q?=3A_Fixes_off-by-one_error_that_was_adding_an_extra_space=2E?= Message-ID: <20161025185229.9291.16821.B2794196@psf.io> https://hg.python.org/cpython/rev/6b46c3deea2c changeset: 104727:6b46c3deea2c branch: 3.6 parent: 104725:84a3c5003510 user: Steve Dower date: Tue Oct 25 11:51:54 2016 -0700 summary: Issue #28333: Fixes off-by-one error that was adding an extra space. files: Parser/myreadline.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -225,7 +225,8 @@ if (wlen) { DWORD n; fflush(stderr); - WriteConsoleW(hStdErr, wbuf, wlen, &n, NULL); + /* wlen includes null terminator, so subtract 1 */ + WriteConsoleW(hStdErr, wbuf, wlen - 1, &n, NULL); } PyMem_RawFree(wbuf); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 21:17:24 2016 From: python-checkins at python.org (martin.panter) Date: Wed, 26 Oct 2016 01:17:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2326240=3A_Merge_subprocess_doc_string_from_3=2E5_into_?= =?utf-8?b?My42?= Message-ID: <20161026011724.25360.63700.EB8569B1@psf.io> https://hg.python.org/cpython/rev/8358c68579e9 changeset: 104730:8358c68579e9 branch: 3.6 parent: 104727:6b46c3deea2c parent: 104729:720865fa61a4 user: Martin Panter date: Tue Oct 25 23:41:42 2016 +0000 summary: Issue #26240: Merge subprocess doc string from 3.5 into 3.6 files: Lib/subprocess.py | 411 ++++++--------------------------- Misc/ACKS | 1 + 2 files changed, 77 insertions(+), 335 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -7,343 +7,38 @@ # Licensed to PSF under a Contributor Agreement. # See http://www.python.org/2.4/license for licensing details. -r"""subprocess - Subprocesses with accessible I/O streams +r"""Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their -input/output/error pipes, and obtain their return codes. This module -intends to replace several older modules and functions: +input/output/error pipes, and obtain their return codes. -os.system -os.spawn* +For a complete description of this module see the Python documentation. -Information about how the subprocess module can be used to replace these -modules and functions can be found below. +Main API +======== +run(...): Runs a command, waits for it to complete, then returns a + CompletedProcess instance. +Popen(...): A class for flexibly executing a command in a new process +Constants +--------- +DEVNULL: Special value that indicates that os.devnull should be used +PIPE: Special value that indicates a pipe should be created +STDOUT: Special value that indicates that stderr should go to stdout -Using the subprocess module -=========================== -This module defines one class called Popen: - -class Popen(args, bufsize=-1, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=True, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0, - restore_signals=True, start_new_session=False, pass_fds=(), - *, encoding=None, errors=None): - - -Arguments are: - -args should be a string, or a sequence of program arguments. The -program to execute is normally the first item in the args sequence or -string, but can be explicitly set by using the executable argument. - -On POSIX, with shell=False (default): In this case, the Popen class -uses os.execvp() to execute the child program. args should normally -be a sequence. A string will be treated as a sequence with the string -as the only item (the program to execute). - -On POSIX, with shell=True: If args is a string, it specifies the -command string to execute through the shell. If args is a sequence, -the first item specifies the command string, and any additional items -will be treated as additional shell arguments. - -On Windows: the 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 list2cmdline method. Please note that -not all MS Windows applications interpret the command line the same -way: The list2cmdline is designed for applications using the same -rules as the MS C runtime. - -bufsize will be supplied as the corresponding argument to the io.open() -function when creating the stdin/stdout/stderr pipe file objects: -0 means unbuffered (read & write are one system call and can return short), -1 means line buffered, any other positive value means use a buffer of -approximately that size. A negative bufsize, the default, means the system -default of io.DEFAULT_BUFFER_SIZE will be used. - -stdin, stdout and stderr specify the executed programs' standard -input, standard output and standard error file handles, respectively. -Valid values are PIPE, an existing file descriptor (a positive -integer), an existing file object, and None. PIPE indicates that a -new pipe to the child should be created. With None, no redirection -will occur; the child's file handles will be inherited from the -parent. Additionally, stderr can be STDOUT, which indicates that the -stderr data from the applications should be captured into the same -file handle as for stdout. - -On POSIX, if preexec_fn is set to a callable object, this object will be -called in the child process just before the child is executed. The use -of preexec_fn is not thread safe, using it in the presence of threads -could lead to a deadlock in the child process before the new executable -is executed. - -If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. The default for close_fds -varies by platform: Always true on POSIX. True when stdin/stdout/stderr -are None on Windows, false otherwise. - -pass_fds is an optional sequence of file descriptors to keep open between the -parent and child. Providing any pass_fds implicitly sets close_fds to true. - -if shell is true, the specified command will be executed through the -shell. - -If cwd is not None, the current directory will be changed to cwd -before the child is executed. - -On POSIX, if restore_signals is True all signals that Python sets to -SIG_IGN are restored to SIG_DFL in the child process before the exec. -Currently this includes the SIGPIPE, SIGXFZ and SIGXFSZ signals. This -parameter does nothing on Windows. - -On POSIX, if start_new_session is True, the setsid() system call will be made -in the child process prior to executing the command. - -If env is not None, it defines the environment variables for the new -process. - -If encoding or errors are specified or universal_newlines is True, the file -objects stdout and stderr are opened in text mode. See io.TextIOWrapper for -the interpretation of these parameters are used. - -If no encoding is specified and universal_newlines is False, the file -objects stdin, stdout and stderr are opened as binary files, and no -line ending conversion is done. - -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) - - -This module also defines some shortcut functions: - -call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> retcode = subprocess.call(["ls", "-l"]) - -check_call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete. If the - exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> subprocess.check_call(["ls", "-l"]) - 0 - -getstatusoutput(cmd): - Return (status, output) of executing cmd in a shell. - - Execute the string 'cmd' in a shell with 'check_output' and - return a 2-tuple (status, output). Universal newlines mode is used, - meaning that the result with be decoded to a string. - - A trailing newline is stripped from the output. - The exit status for the command can be interpreted - according to the rules for the function 'wait'. Example: - - >>> subprocess.getstatusoutput('ls /bin/ls') - (0, '/bin/ls') - >>> subprocess.getstatusoutput('cat /bin/junk') - (256, 'cat: /bin/junk: No such file or directory') - >>> subprocess.getstatusoutput('/bin/junk') - (256, 'sh: /bin/junk: not found') - -getoutput(cmd): - Return output (stdout or stderr) of executing cmd in a shell. - - Like getstatusoutput(), except the exit status is ignored and the return - value is a string containing the command's output. Example: - - >>> subprocess.getoutput('ls /bin/ls') - '/bin/ls' - -check_output(*popenargs, **kwargs): - Run command with arguments and return its output. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> output = subprocess.check_output(["ls", "-l", "/dev/null"]) - - There is an additional optional argument, "input", allowing you to - pass a string to the subprocess's stdin. If you use this argument - you may not also use the Popen constructor's "stdin" argument. - - If universal_newlines is set to True, the "input" argument must - be a string rather than bytes, and the return value will be a string. - -Exceptions ----------- -Exceptions raised in the child process, before the new program has -started to execute, will be re-raised in the parent. Additionally, -the exception object will have one extra attribute called -'child_traceback', which is a string containing traceback information -from the child's point of view. - -The most common exception raised is OSError. This occurs, for -example, when trying to execute a non-existent file. Applications -should prepare for OSErrors. - -A ValueError will be raised if Popen is called with invalid arguments. - -Exceptions defined within this module inherit from SubprocessError. -check_call() and check_output() will raise CalledProcessError if the -called process returns a non-zero return code. TimeoutExpired -be raised if a timeout was specified and expired. - - -Security --------- -Unlike some other popen functions, this implementation will never call -/bin/sh implicitly. This means that all characters, including shell -metacharacters, can safely be passed to child processes. - - -Popen objects -============= -Instances of the Popen class have the following methods: - -poll() - Check if child process has terminated. Returns returncode - attribute. - -wait() - Wait for child process to terminate. Returns returncode attribute. - -communicate(input=None) - Interact with process: Send data to stdin. Read data from stdout - and stderr, until end-of-file is reached. Wait for process to - terminate. The optional input argument should be data to be - sent to the child process, or None, if no data should be sent to - the child. If the Popen instance was constructed in text mode, the - input argument should be a string. Otherwise, it should be bytes. - - communicate() returns a tuple (stdout, stderr). - - Note: The data read is buffered in memory, so do not use this - method if the data size is large or unlimited. - -The following attributes are also available: - -stdin - If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - -stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is - None. - -stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - -pid - The process ID of the child process. - -returncode - The child return code. A None value indicates that the process - hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (POSIX only). - - -Replacing older functions with the subprocess module -==================================================== -In this section, "a ==> b" means that b can be used as a replacement -for a. - -Note: All functions in this section fail (more or less) silently if -the executed program cannot be found; this module raises an OSError -exception. - -In the following examples, we assume that the subprocess module is -imported with "from subprocess import *". - - -Replacing /bin/sh shell backquote ---------------------------------- -output=`mycmd myarg` -==> -output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] - - -Replacing shell pipe line -------------------------- -output=`dmesg | grep hda` -==> -p1 = Popen(["dmesg"], stdout=PIPE) -p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) -output = p2.communicate()[0] - - -Replacing os.system() ---------------------- -sts = os.system("mycmd" + " myarg") -==> -p = Popen("mycmd" + " myarg", shell=True) -pid, sts = os.waitpid(p.pid, 0) - -Note: - -* Calling the program through the shell is usually not required. - -* It's easier to look at the returncode attribute than the - exitstatus. - -A more real-world example would look like this: - -try: - retcode = call("mycmd" + " myarg", shell=True) - if retcode < 0: - print("Child was terminated by signal", -retcode, file=sys.stderr) - else: - print("Child returned", retcode, file=sys.stderr) -except OSError as e: - print("Execution failed:", e, file=sys.stderr) - - -Replacing os.spawn* -------------------- -P_NOWAIT example: - -pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") -==> -pid = Popen(["/bin/mycmd", "myarg"]).pid - - -P_WAIT example: - -retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") -==> -retcode = call(["/bin/mycmd", "myarg"]) - - -Vector example: - -os.spawnvp(os.P_NOWAIT, path, args) -==> -Popen([path] + args[1:]) - - -Environment example: - -os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) -==> -Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) +Older API +========= +call(...): Runs a command, waits for it to complete, then returns + the return code. +check_call(...): Same as call() but raises CalledProcessError() + if return code is not 0 +check_output(...): Same as check_call() but returns the contents of + stdout instead of a return code +getoutput(...): Runs a command in the shell, waits for it to complete, + then returns the output +getstatusoutput(...): Runs a command in the shell, waits for it to complete, + then returns a (status, output) tuple """ import sys @@ -363,12 +58,11 @@ class CalledProcessError(SubprocessError): - """Raised when a check_call() or check_output() process returns non-zero. + """Raised when run() is called with check=True and the process + returns a non-zero exit status. - The exit status will be stored in the returncode attribute, negative - if it represents a signal number. - - check_output() will also store the output in the output attribute. + Attributes: + cmd, returncode, stdout, stderr, output """ def __init__(self, returncode, cmd, output=None, stderr=None): self.returncode = returncode @@ -403,6 +97,9 @@ class TimeoutExpired(SubprocessError): """This exception is raised when the timeout expires while waiting for a child process. + + Attributes: + cmd, output, stdout, stderr, timeout """ def __init__(self, cmd, timeout, output=None, stderr=None): self.cmd = cmd @@ -841,7 +538,49 @@ class Popen(object): + """ Execute a child program in a new process. + For a complete description of the arguments see the Python documentation. + + Arguments: + args: A string, or a sequence of program arguments. + + bufsize: supplied as the buffering argument to the open() function when + creating the stdin/stdout/stderr pipe file objects + + executable: A replacement program to execute. + + stdin, stdout and stderr: These specify the executed programs' standard + input, standard output and standard error file handles, respectively. + + preexec_fn: (POSIX only) An object to be called in the child process + just before the child is executed. + + close_fds: Controls closing or inheriting of file descriptors. + + shell: If true, the command will be executed through the shell. + + cwd: Sets the current directory before the child is executed. + + env: Defines the environment variables for the new process. + + universal_newlines: If true, use universal line endings for file + objects stdin, stdout and stderr. + + startupinfo and creationflags (Windows only) + + restore_signals (POSIX only) + + start_new_session (POSIX only) + + pass_fds (POSIX only) + + encoding and errors: Text mode encoding and error handling to use for + file objects stdin, stdout and stderr. + + Attributes: + stdin, stdout, stderr, pid, returncode + """ _child_created = False # Set here since __del__ checks it def __init__(self, args, bufsize=-1, executable=None, @@ -1104,6 +843,8 @@ def poll(self): + """Check if child process has terminated. Set and return returncode + attribute.""" return self._internal_poll() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1013,6 +1013,7 @@ Andrii V. Mishkovskyi Dom Mitchell Dustin J. Mitchell +Tim Mitchell Zubin Mithra Florian Mladitsch Doug Moen -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 21:17:24 2016 From: python-checkins at python.org (martin.panter) Date: Wed, 26 Oct 2016 01:17:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2MjQw?= =?utf-8?q?=3A_Clean_up_the_subprocess_module_doc_string?= Message-ID: <20161026011724.62100.79971.8F97E763@psf.io> https://hg.python.org/cpython/rev/720865fa61a4 changeset: 104729:720865fa61a4 branch: 3.5 parent: 104724:470224ec16b6 user: Martin Panter date: Tue Oct 25 22:20:48 2016 +0000 summary: Issue #26240: Clean up the subprocess module doc string Patch by Tim Mitchell. files: Lib/subprocess.py | 417 ++++++--------------------------- Misc/ACKS | 1 + 2 files changed, 75 insertions(+), 343 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -7,352 +7,38 @@ # Licensed to PSF under a Contributor Agreement. # See http://www.python.org/2.4/license for licensing details. -r"""subprocess - Subprocesses with accessible I/O streams +r"""Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their -input/output/error pipes, and obtain their return codes. This module -intends to replace several older modules and functions: +input/output/error pipes, and obtain their return codes. -os.system -os.spawn* +For a complete description of this module see the Python documentation. -Information about how the subprocess module can be used to replace these -modules and functions can be found below. +Main API +======== +run(...): Runs a command, waits for it to complete, then returns a + CompletedProcess instance. +Popen(...): A class for flexibly executing a command in a new process +Constants +--------- +DEVNULL: Special value that indicates that os.devnull should be used +PIPE: Special value that indicates a pipe should be created +STDOUT: Special value that indicates that stderr should go to stdout -Using the subprocess module -=========================== -This module defines one class called Popen: - -class Popen(args, bufsize=-1, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=True, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0, - restore_signals=True, start_new_session=False, pass_fds=()): - - -Arguments are: - -args should be a string, or a sequence of program arguments. The -program to execute is normally the first item in the args sequence or -string, but can be explicitly set by using the executable argument. - -On POSIX, with shell=False (default): In this case, the Popen class -uses os.execvp() to execute the child program. args should normally -be a sequence. A string will be treated as a sequence with the string -as the only item (the program to execute). - -On POSIX, with shell=True: If args is a string, it specifies the -command string to execute through the shell. If args is a sequence, -the first item specifies the command string, and any additional items -will be treated as additional shell arguments. - -On Windows: the 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 list2cmdline method. Please note that -not all MS Windows applications interpret the command line the same -way: The list2cmdline is designed for applications using the same -rules as the MS C runtime. - -bufsize will be supplied as the corresponding argument to the io.open() -function when creating the stdin/stdout/stderr pipe file objects: -0 means unbuffered (read & write are one system call and can return short), -1 means line buffered, any other positive value means use a buffer of -approximately that size. A negative bufsize, the default, means the system -default of io.DEFAULT_BUFFER_SIZE will be used. - -stdin, stdout and stderr specify the executed programs' standard -input, standard output and standard error file handles, respectively. -Valid values are PIPE, an existing file descriptor (a positive -integer), an existing file object, and None. PIPE indicates that a -new pipe to the child should be created. With None, no redirection -will occur; the child's file handles will be inherited from the -parent. Additionally, stderr can be STDOUT, which indicates that the -stderr data from the applications should be captured into the same -file handle as for stdout. - -On POSIX, if preexec_fn is set to a callable object, this object will be -called in the child process just before the child is executed. The use -of preexec_fn is not thread safe, using it in the presence of threads -could lead to a deadlock in the child process before the new executable -is executed. - -If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. The default for close_fds -varies by platform: Always true on POSIX. True when stdin/stdout/stderr -are None on Windows, false otherwise. - -pass_fds is an optional sequence of file descriptors to keep open between the -parent and child. Providing any pass_fds implicitly sets close_fds to true. - -if shell is true, the specified command will be executed through the -shell. - -If cwd is not None, the current directory will be changed to cwd -before the child is executed. - -On POSIX, if restore_signals is True all signals that Python sets to -SIG_IGN are restored to SIG_DFL in the child process before the exec. -Currently this includes the SIGPIPE, SIGXFZ and SIGXFSZ signals. This -parameter does nothing on Windows. - -On POSIX, if start_new_session is True, the setsid() system call will be made -in the child process prior to executing the command. - -If env is not None, it defines the environment variables for the new -process. - -If universal_newlines is False, the file objects stdin, stdout and stderr -are opened as binary files, and no line ending conversion is done. - -If universal_newlines is True, the file objects stdout and stderr are -opened as a text file, but lines may be terminated by any of '\n', -the Unix end-of-line convention, '\r', the old Macintosh convention or -'\r\n', the Windows convention. All of these external representations -are seen as '\n' by the Python program. Also, the newlines attribute -of the file objects stdout, stdin and stderr are not updated by the -communicate() method. - -In either case, the process being communicated with should start up -expecting to receive bytes on its standard input and decode them with -the same encoding they are sent in. - -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) - - -This module also defines some shortcut functions: - -call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> retcode = subprocess.call(["ls", "-l"]) - -check_call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete. If the - exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> subprocess.check_call(["ls", "-l"]) - 0 - -getstatusoutput(cmd): - Return (status, output) of executing cmd in a shell. - - Execute the string 'cmd' in a shell with 'check_output' and - return a 2-tuple (status, output). Universal newlines mode is used, - meaning that the result with be decoded to a string. - - A trailing newline is stripped from the output. - The exit status for the command can be interpreted - according to the rules for the function 'wait'. Example: - - >>> subprocess.getstatusoutput('ls /bin/ls') - (0, '/bin/ls') - >>> subprocess.getstatusoutput('cat /bin/junk') - (256, 'cat: /bin/junk: No such file or directory') - >>> subprocess.getstatusoutput('/bin/junk') - (256, 'sh: /bin/junk: not found') - -getoutput(cmd): - Return output (stdout or stderr) of executing cmd in a shell. - - Like getstatusoutput(), except the exit status is ignored and the return - value is a string containing the command's output. Example: - - >>> subprocess.getoutput('ls /bin/ls') - '/bin/ls' - -check_output(*popenargs, **kwargs): - Run command with arguments and return its output. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> output = subprocess.check_output(["ls", "-l", "/dev/null"]) - - There is an additional optional argument, "input", allowing you to - pass a string to the subprocess's stdin. If you use this argument - you may not also use the Popen constructor's "stdin" argument. - - If universal_newlines is set to True, the "input" argument must - be a string rather than bytes, and the return value will be a string. - -Exceptions ----------- -Exceptions raised in the child process, before the new program has -started to execute, will be re-raised in the parent. Additionally, -the exception object will have one extra attribute called -'child_traceback', which is a string containing traceback information -from the child's point of view. - -The most common exception raised is OSError. This occurs, for -example, when trying to execute a non-existent file. Applications -should prepare for OSErrors. - -A ValueError will be raised if Popen is called with invalid arguments. - -Exceptions defined within this module inherit from SubprocessError. -check_call() and check_output() will raise CalledProcessError if the -called process returns a non-zero return code. TimeoutExpired -be raised if a timeout was specified and expired. - - -Security --------- -Unlike some other popen functions, this implementation will never call -/bin/sh implicitly. This means that all characters, including shell -metacharacters, can safely be passed to child processes. - - -Popen objects -============= -Instances of the Popen class have the following methods: - -poll() - Check if child process has terminated. Returns returncode - attribute. - -wait() - Wait for child process to terminate. Returns returncode attribute. - -communicate(input=None) - Interact with process: Send data to stdin. Read data from stdout - and stderr, until end-of-file is reached. Wait for process to - terminate. The optional input argument should be data to be - sent to the child process, or None, if no data should be sent to - the child. If the Popen instance was constructed with universal_newlines - set to True, the input argument should be a string and will be encoded - using the preferred system encoding (see locale.getpreferredencoding); - if universal_newlines is False, the input argument should be a - byte string. - - communicate() returns a tuple (stdout, stderr). - - Note: The data read is buffered in memory, so do not use this - method if the data size is large or unlimited. - -The following attributes are also available: - -stdin - If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - -stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is - None. - -stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - -pid - The process ID of the child process. - -returncode - The child return code. A None value indicates that the process - hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (POSIX only). - - -Replacing older functions with the subprocess module -==================================================== -In this section, "a ==> b" means that b can be used as a replacement -for a. - -Note: All functions in this section fail (more or less) silently if -the executed program cannot be found; this module raises an OSError -exception. - -In the following examples, we assume that the subprocess module is -imported with "from subprocess import *". - - -Replacing /bin/sh shell backquote ---------------------------------- -output=`mycmd myarg` -==> -output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] - - -Replacing shell pipe line -------------------------- -output=`dmesg | grep hda` -==> -p1 = Popen(["dmesg"], stdout=PIPE) -p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) -output = p2.communicate()[0] - - -Replacing os.system() ---------------------- -sts = os.system("mycmd" + " myarg") -==> -p = Popen("mycmd" + " myarg", shell=True) -pid, sts = os.waitpid(p.pid, 0) - -Note: - -* Calling the program through the shell is usually not required. - -* It's easier to look at the returncode attribute than the - exitstatus. - -A more real-world example would look like this: - -try: - retcode = call("mycmd" + " myarg", shell=True) - if retcode < 0: - print("Child was terminated by signal", -retcode, file=sys.stderr) - else: - print("Child returned", retcode, file=sys.stderr) -except OSError as e: - print("Execution failed:", e, file=sys.stderr) - - -Replacing os.spawn* -------------------- -P_NOWAIT example: - -pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") -==> -pid = Popen(["/bin/mycmd", "myarg"]).pid - - -P_WAIT example: - -retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") -==> -retcode = call(["/bin/mycmd", "myarg"]) - - -Vector example: - -os.spawnvp(os.P_NOWAIT, path, args) -==> -Popen([path] + args[1:]) - - -Environment example: - -os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) -==> -Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) +Older API +========= +call(...): Runs a command, waits for it to complete, then returns + the return code. +check_call(...): Same as call() but raises CalledProcessError() + if return code is not 0 +check_output(...): Same as check_call() but returns the contents of + stdout instead of a return code +getoutput(...): Runs a command in the shell, waits for it to complete, + then returns the output +getstatusoutput(...): Runs a command in the shell, waits for it to complete, + then returns a (status, output) tuple """ import sys @@ -372,10 +58,11 @@ class CalledProcessError(SubprocessError): - """This exception is raised when a process run by check_call() or - check_output() returns a non-zero exit status. - The exit status will be stored in the returncode attribute; - check_output() will also store the output in the output attribute. + """Raised when run() is called with check=True and the process + returns a non-zero exit status. + + Attributes: + cmd, returncode, stdout, stderr, output """ def __init__(self, returncode, cmd, output=None, stderr=None): self.returncode = returncode @@ -401,6 +88,9 @@ class TimeoutExpired(SubprocessError): """This exception is raised when the timeout expires while waiting for a child process. + + Attributes: + cmd, output, stdout, stderr, timeout """ def __init__(self, cmd, timeout, output=None, stderr=None): self.cmd = cmd @@ -828,7 +518,46 @@ class Popen(object): + """ Execute a child program in a new process. + For a complete description of the arguments see the Python documentation. + + Arguments: + args: A string, or a sequence of program arguments. + + bufsize: supplied as the buffering argument to the open() function when + creating the stdin/stdout/stderr pipe file objects + + executable: A replacement program to execute. + + stdin, stdout and stderr: These specify the executed programs' standard + input, standard output and standard error file handles, respectively. + + preexec_fn: (POSIX only) An object to be called in the child process + just before the child is executed. + + close_fds: Controls closing or inheriting of file descriptors. + + shell: If true, the command will be executed through the shell. + + cwd: Sets the current directory before the child is executed. + + env: Defines the environment variables for the new process. + + universal_newlines: If true, use universal line endings for file + objects stdin, stdout and stderr. + + startupinfo and creationflags (Windows only) + + restore_signals (POSIX only) + + start_new_session (POSIX only) + + pass_fds (POSIX only) + + Attributes: + stdin, stdout, stderr, pid, returncode + """ _child_created = False # Set here since __del__ checks it def __init__(self, args, bufsize=-1, executable=None, @@ -1079,6 +808,8 @@ def poll(self): + """Check if child process has terminated. Set and return returncode + attribute.""" return self._internal_poll() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -999,6 +999,7 @@ Andrii V. Mishkovskyi Dom Mitchell Dustin J. Mitchell +Tim Mitchell Zubin Mithra Florian Mladitsch Doug Moen -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 21:17:24 2016 From: python-checkins at python.org (martin.panter) Date: Wed, 26 Oct 2016 01:17:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326240=3A_Merge_subprocess_doc_string_from_3=2E6?= Message-ID: <20161026011724.81250.49725.B6DF700B@psf.io> https://hg.python.org/cpython/rev/0dd8b3f133f9 changeset: 104731:0dd8b3f133f9 parent: 104728:44d15ba67d2e parent: 104730:8358c68579e9 user: Martin Panter date: Wed Oct 26 00:26:38 2016 +0000 summary: Issue #26240: Merge subprocess doc string from 3.6 files: Lib/subprocess.py | 411 ++++++--------------------------- Misc/ACKS | 1 + 2 files changed, 77 insertions(+), 335 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -7,343 +7,38 @@ # Licensed to PSF under a Contributor Agreement. # See http://www.python.org/2.4/license for licensing details. -r"""subprocess - Subprocesses with accessible I/O streams +r"""Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their -input/output/error pipes, and obtain their return codes. This module -intends to replace several older modules and functions: +input/output/error pipes, and obtain their return codes. -os.system -os.spawn* +For a complete description of this module see the Python documentation. -Information about how the subprocess module can be used to replace these -modules and functions can be found below. +Main API +======== +run(...): Runs a command, waits for it to complete, then returns a + CompletedProcess instance. +Popen(...): A class for flexibly executing a command in a new process +Constants +--------- +DEVNULL: Special value that indicates that os.devnull should be used +PIPE: Special value that indicates a pipe should be created +STDOUT: Special value that indicates that stderr should go to stdout -Using the subprocess module -=========================== -This module defines one class called Popen: - -class Popen(args, bufsize=-1, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=True, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0, - restore_signals=True, start_new_session=False, pass_fds=(), - *, encoding=None, errors=None): - - -Arguments are: - -args should be a string, or a sequence of program arguments. The -program to execute is normally the first item in the args sequence or -string, but can be explicitly set by using the executable argument. - -On POSIX, with shell=False (default): In this case, the Popen class -uses os.execvp() to execute the child program. args should normally -be a sequence. A string will be treated as a sequence with the string -as the only item (the program to execute). - -On POSIX, with shell=True: If args is a string, it specifies the -command string to execute through the shell. If args is a sequence, -the first item specifies the command string, and any additional items -will be treated as additional shell arguments. - -On Windows: the 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 list2cmdline method. Please note that -not all MS Windows applications interpret the command line the same -way: The list2cmdline is designed for applications using the same -rules as the MS C runtime. - -bufsize will be supplied as the corresponding argument to the io.open() -function when creating the stdin/stdout/stderr pipe file objects: -0 means unbuffered (read & write are one system call and can return short), -1 means line buffered, any other positive value means use a buffer of -approximately that size. A negative bufsize, the default, means the system -default of io.DEFAULT_BUFFER_SIZE will be used. - -stdin, stdout and stderr specify the executed programs' standard -input, standard output and standard error file handles, respectively. -Valid values are PIPE, an existing file descriptor (a positive -integer), an existing file object, and None. PIPE indicates that a -new pipe to the child should be created. With None, no redirection -will occur; the child's file handles will be inherited from the -parent. Additionally, stderr can be STDOUT, which indicates that the -stderr data from the applications should be captured into the same -file handle as for stdout. - -On POSIX, if preexec_fn is set to a callable object, this object will be -called in the child process just before the child is executed. The use -of preexec_fn is not thread safe, using it in the presence of threads -could lead to a deadlock in the child process before the new executable -is executed. - -If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. The default for close_fds -varies by platform: Always true on POSIX. True when stdin/stdout/stderr -are None on Windows, false otherwise. - -pass_fds is an optional sequence of file descriptors to keep open between the -parent and child. Providing any pass_fds implicitly sets close_fds to true. - -if shell is true, the specified command will be executed through the -shell. - -If cwd is not None, the current directory will be changed to cwd -before the child is executed. - -On POSIX, if restore_signals is True all signals that Python sets to -SIG_IGN are restored to SIG_DFL in the child process before the exec. -Currently this includes the SIGPIPE, SIGXFZ and SIGXFSZ signals. This -parameter does nothing on Windows. - -On POSIX, if start_new_session is True, the setsid() system call will be made -in the child process prior to executing the command. - -If env is not None, it defines the environment variables for the new -process. - -If encoding or errors are specified or universal_newlines is True, the file -objects stdout and stderr are opened in text mode. See io.TextIOWrapper for -the interpretation of these parameters are used. - -If no encoding is specified and universal_newlines is False, the file -objects stdin, stdout and stderr are opened as binary files, and no -line ending conversion is done. - -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) - - -This module also defines some shortcut functions: - -call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> retcode = subprocess.call(["ls", "-l"]) - -check_call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete. If the - exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> subprocess.check_call(["ls", "-l"]) - 0 - -getstatusoutput(cmd): - Return (status, output) of executing cmd in a shell. - - Execute the string 'cmd' in a shell with 'check_output' and - return a 2-tuple (status, output). Universal newlines mode is used, - meaning that the result with be decoded to a string. - - A trailing newline is stripped from the output. - The exit status for the command can be interpreted - according to the rules for the function 'wait'. Example: - - >>> subprocess.getstatusoutput('ls /bin/ls') - (0, '/bin/ls') - >>> subprocess.getstatusoutput('cat /bin/junk') - (256, 'cat: /bin/junk: No such file or directory') - >>> subprocess.getstatusoutput('/bin/junk') - (256, 'sh: /bin/junk: not found') - -getoutput(cmd): - Return output (stdout or stderr) of executing cmd in a shell. - - Like getstatusoutput(), except the exit status is ignored and the return - value is a string containing the command's output. Example: - - >>> subprocess.getoutput('ls /bin/ls') - '/bin/ls' - -check_output(*popenargs, **kwargs): - Run command with arguments and return its output. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> output = subprocess.check_output(["ls", "-l", "/dev/null"]) - - There is an additional optional argument, "input", allowing you to - pass a string to the subprocess's stdin. If you use this argument - you may not also use the Popen constructor's "stdin" argument. - - If universal_newlines is set to True, the "input" argument must - be a string rather than bytes, and the return value will be a string. - -Exceptions ----------- -Exceptions raised in the child process, before the new program has -started to execute, will be re-raised in the parent. Additionally, -the exception object will have one extra attribute called -'child_traceback', which is a string containing traceback information -from the child's point of view. - -The most common exception raised is OSError. This occurs, for -example, when trying to execute a non-existent file. Applications -should prepare for OSErrors. - -A ValueError will be raised if Popen is called with invalid arguments. - -Exceptions defined within this module inherit from SubprocessError. -check_call() and check_output() will raise CalledProcessError if the -called process returns a non-zero return code. TimeoutExpired -be raised if a timeout was specified and expired. - - -Security --------- -Unlike some other popen functions, this implementation will never call -/bin/sh implicitly. This means that all characters, including shell -metacharacters, can safely be passed to child processes. - - -Popen objects -============= -Instances of the Popen class have the following methods: - -poll() - Check if child process has terminated. Returns returncode - attribute. - -wait() - Wait for child process to terminate. Returns returncode attribute. - -communicate(input=None) - Interact with process: Send data to stdin. Read data from stdout - and stderr, until end-of-file is reached. Wait for process to - terminate. The optional input argument should be data to be - sent to the child process, or None, if no data should be sent to - the child. If the Popen instance was constructed in text mode, the - input argument should be a string. Otherwise, it should be bytes. - - communicate() returns a tuple (stdout, stderr). - - Note: The data read is buffered in memory, so do not use this - method if the data size is large or unlimited. - -The following attributes are also available: - -stdin - If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - -stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is - None. - -stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - -pid - The process ID of the child process. - -returncode - The child return code. A None value indicates that the process - hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (POSIX only). - - -Replacing older functions with the subprocess module -==================================================== -In this section, "a ==> b" means that b can be used as a replacement -for a. - -Note: All functions in this section fail (more or less) silently if -the executed program cannot be found; this module raises an OSError -exception. - -In the following examples, we assume that the subprocess module is -imported with "from subprocess import *". - - -Replacing /bin/sh shell backquote ---------------------------------- -output=`mycmd myarg` -==> -output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] - - -Replacing shell pipe line -------------------------- -output=`dmesg | grep hda` -==> -p1 = Popen(["dmesg"], stdout=PIPE) -p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) -output = p2.communicate()[0] - - -Replacing os.system() ---------------------- -sts = os.system("mycmd" + " myarg") -==> -p = Popen("mycmd" + " myarg", shell=True) -pid, sts = os.waitpid(p.pid, 0) - -Note: - -* Calling the program through the shell is usually not required. - -* It's easier to look at the returncode attribute than the - exitstatus. - -A more real-world example would look like this: - -try: - retcode = call("mycmd" + " myarg", shell=True) - if retcode < 0: - print("Child was terminated by signal", -retcode, file=sys.stderr) - else: - print("Child returned", retcode, file=sys.stderr) -except OSError as e: - print("Execution failed:", e, file=sys.stderr) - - -Replacing os.spawn* -------------------- -P_NOWAIT example: - -pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") -==> -pid = Popen(["/bin/mycmd", "myarg"]).pid - - -P_WAIT example: - -retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") -==> -retcode = call(["/bin/mycmd", "myarg"]) - - -Vector example: - -os.spawnvp(os.P_NOWAIT, path, args) -==> -Popen([path] + args[1:]) - - -Environment example: - -os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) -==> -Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) +Older API +========= +call(...): Runs a command, waits for it to complete, then returns + the return code. +check_call(...): Same as call() but raises CalledProcessError() + if return code is not 0 +check_output(...): Same as check_call() but returns the contents of + stdout instead of a return code +getoutput(...): Runs a command in the shell, waits for it to complete, + then returns the output +getstatusoutput(...): Runs a command in the shell, waits for it to complete, + then returns a (status, output) tuple """ import sys @@ -363,12 +58,11 @@ class CalledProcessError(SubprocessError): - """Raised when a check_call() or check_output() process returns non-zero. + """Raised when run() is called with check=True and the process + returns a non-zero exit status. - The exit status will be stored in the returncode attribute, negative - if it represents a signal number. - - check_output() will also store the output in the output attribute. + Attributes: + cmd, returncode, stdout, stderr, output """ def __init__(self, returncode, cmd, output=None, stderr=None): self.returncode = returncode @@ -403,6 +97,9 @@ class TimeoutExpired(SubprocessError): """This exception is raised when the timeout expires while waiting for a child process. + + Attributes: + cmd, output, stdout, stderr, timeout """ def __init__(self, cmd, timeout, output=None, stderr=None): self.cmd = cmd @@ -841,7 +538,49 @@ class Popen(object): + """ Execute a child program in a new process. + For a complete description of the arguments see the Python documentation. + + Arguments: + args: A string, or a sequence of program arguments. + + bufsize: supplied as the buffering argument to the open() function when + creating the stdin/stdout/stderr pipe file objects + + executable: A replacement program to execute. + + stdin, stdout and stderr: These specify the executed programs' standard + input, standard output and standard error file handles, respectively. + + preexec_fn: (POSIX only) An object to be called in the child process + just before the child is executed. + + close_fds: Controls closing or inheriting of file descriptors. + + shell: If true, the command will be executed through the shell. + + cwd: Sets the current directory before the child is executed. + + env: Defines the environment variables for the new process. + + universal_newlines: If true, use universal line endings for file + objects stdin, stdout and stderr. + + startupinfo and creationflags (Windows only) + + restore_signals (POSIX only) + + start_new_session (POSIX only) + + pass_fds (POSIX only) + + encoding and errors: Text mode encoding and error handling to use for + file objects stdin, stdout and stderr. + + Attributes: + stdin, stdout, stderr, pid, returncode + """ _child_created = False # Set here since __del__ checks it def __init__(self, args, bufsize=-1, executable=None, @@ -1104,6 +843,8 @@ def poll(self): + """Check if child process has terminated. Set and return returncode + attribute.""" return self._internal_poll() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1014,6 +1014,7 @@ Andrii V. Mishkovskyi Dom Mitchell Dustin J. Mitchell +Tim Mitchell Zubin Mithra Florian Mladitsch Doug Moen -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 21:17:25 2016 From: python-checkins at python.org (martin.panter) Date: Wed, 26 Oct 2016 01:17:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI2MjQw?= =?utf-8?q?=3A_Clean_up_the_subprocess_module_doc_string?= Message-ID: <20161026011725.49488.6310.300857E7@psf.io> https://hg.python.org/cpython/rev/5a1edf5701f1 changeset: 104732:5a1edf5701f1 branch: 2.7 parent: 104690:77571b528f6a user: Martin Panter date: Wed Oct 26 00:44:31 2016 +0000 summary: Issue #26240: Clean up the subprocess module doc string Patch by Tim Mitchell. files: Lib/subprocess.py | 429 ++++----------------------------- Misc/ACKS | 1 + 2 files changed, 56 insertions(+), 374 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -7,383 +7,27 @@ # Licensed to PSF under a Contributor Agreement. # See http://www.python.org/2.4/license for licensing details. -r"""subprocess - Subprocesses with accessible I/O streams +r"""Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their -input/output/error pipes, and obtain their return codes. This module -intends to replace several older modules and functions: +input/output/error pipes, and obtain their return codes. -os.system -os.spawn* -os.popen* -popen2.* -commands.* +For a complete description of this module see the Python documentation. -Information about how the subprocess module can be used to replace these -modules and functions can be found below. +Main API +======== +call(...): Runs a command, waits for it to complete, then returns + the return code. +check_call(...): Same as call() but raises CalledProcessError() + if return code is not 0 +check_output(...): Same as check_call() but returns the contents of + stdout instead of a return code +Popen(...): A class for flexibly executing a command in a new process - - -Using the subprocess module -=========================== -This module defines one class called Popen: - -class Popen(args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0): - - -Arguments are: - -args should be a string, or a sequence of program arguments. The -program to execute is normally the first item in the args sequence or -string, but can be explicitly set by using the executable argument. - -On UNIX, with shell=False (default): In this case, the Popen class -uses os.execvp() to execute the child program. args should normally -be a sequence. A string will be treated as a sequence with the string -as the only item (the program to execute). - -On UNIX, with shell=True: If args is a string, it specifies the -command string to execute through the shell. If args is a sequence, -the first item specifies the command string, and any additional items -will be treated as additional shell arguments. - -On Windows: the 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 list2cmdline method. Please note that -not all MS Windows applications interpret the command line the same -way: The list2cmdline is designed for applications using the same -rules as the MS C runtime. - -bufsize, if given, has the same meaning as the corresponding argument -to the built-in open() function: 0 means unbuffered, 1 means line -buffered, any other positive value means use a buffer of -(approximately) that size. A negative bufsize means to use the system -default, which usually means fully buffered. The default value for -bufsize is 0 (unbuffered). - -stdin, stdout and stderr specify the executed programs' standard -input, standard output and standard error file handles, respectively. -Valid values are PIPE, an existing file descriptor (a positive -integer), an existing file object, and None. PIPE indicates that a -new pipe to the child should be created. With None, no redirection -will occur; the child's file handles will be inherited from the -parent. Additionally, stderr can be STDOUT, which indicates that the -stderr data from the applications should be captured into the same -file handle as for stdout. - -If preexec_fn is set to a callable object, this object will be called -in the child process just before the child is executed. - -If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. - -if shell is true, the specified command will be executed through the -shell. - -If cwd is not None, the current directory will be changed to cwd -before the child is executed. - -If env is not None, it defines the environment variables for the new -process. - -If universal_newlines is true, the file objects stdout and stderr are -opened as a text files, but lines may be terminated by any of '\n', -the Unix end-of-line convention, '\r', the Macintosh convention or -'\r\n', the Windows convention. All of these external representations -are seen as '\n' by the Python program. Note: This feature is only -available if Python is built with universal newline support (the -default). Also, the newlines attribute of the file objects stdout, -stdin and 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) - - -This module also defines some shortcut functions: - -call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - retcode = call(["ls", "-l"]) - -check_call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete. If the - exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - check_call(["ls", "-l"]) - -check_output(*popenargs, **kwargs): - Run command with arguments and return its output as a byte string. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - output = check_output(["ls", "-l", "/dev/null"]) - - -Exceptions ----------- -Exceptions raised in the child process, before the new program has -started to execute, will be re-raised in the parent. Additionally, -the exception object will have one extra attribute called -'child_traceback', which is a string containing traceback information -from the child's point of view. - -The most common exception raised is OSError. This occurs, for -example, when trying to execute a non-existent file. Applications -should prepare for OSErrors. - -A ValueError will be raised if Popen is called with invalid arguments. - -check_call() and check_output() will raise CalledProcessError, if the -called process returns a non-zero return code. - - -Security --------- -Unlike some other popen functions, this implementation will never call -/bin/sh implicitly. This means that all characters, including shell -metacharacters, can safely be passed to child processes. - - -Popen objects -============= -Instances of the Popen class have the following methods: - -poll() - Check if child process has terminated. Returns returncode - attribute. - -wait() - Wait for child process to terminate. Returns returncode attribute. - -communicate(input=None) - Interact with process: Send data to stdin. Read data from stdout - and stderr, until end-of-file is reached. Wait for process to - terminate. The optional input argument should be a string to be - sent to the child process, or None, if no data should be sent to - the child. - - communicate() returns a tuple (stdout, stderr). - - Note: The data read is buffered in memory, so do not use this - method if the data size is large or unlimited. - -The following attributes are also available: - -stdin - If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - -stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is - None. - -stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - -pid - The process ID of the child process. - -returncode - The child return code. A None value indicates that the process - hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (UNIX only). - - -Replacing older functions with the subprocess module -==================================================== -In this section, "a ==> b" means that b can be used as a replacement -for a. - -Note: All functions in this section fail (more or less) silently if -the executed program cannot be found; this module raises an OSError -exception. - -In the following examples, we assume that the subprocess module is -imported with "from subprocess import *". - - -Replacing /bin/sh shell backquote ---------------------------------- -output=`mycmd myarg` -==> -output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] - - -Replacing shell pipe line -------------------------- -output=`dmesg | grep hda` -==> -p1 = Popen(["dmesg"], stdout=PIPE) -p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) -output = p2.communicate()[0] - - -Replacing os.system() ---------------------- -sts = os.system("mycmd" + " myarg") -==> -p = Popen("mycmd" + " myarg", shell=True) -pid, sts = os.waitpid(p.pid, 0) - -Note: - -* Calling the program through the shell is usually not required. - -* It's easier to look at the returncode attribute than the - exitstatus. - -A more real-world example would look like this: - -try: - retcode = call("mycmd" + " myarg", shell=True) - if retcode < 0: - print >>sys.stderr, "Child was terminated by signal", -retcode - else: - print >>sys.stderr, "Child returned", retcode -except OSError, e: - print >>sys.stderr, "Execution failed:", e - - -Replacing os.spawn* -------------------- -P_NOWAIT example: - -pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") -==> -pid = Popen(["/bin/mycmd", "myarg"]).pid - - -P_WAIT example: - -retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") -==> -retcode = call(["/bin/mycmd", "myarg"]) - - -Vector example: - -os.spawnvp(os.P_NOWAIT, path, args) -==> -Popen([path] + args[1:]) - - -Environment example: - -os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) -==> -Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) - - -Replacing os.popen* -------------------- -pipe = os.popen("cmd", mode='r', bufsize) -==> -pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout - -pipe = os.popen("cmd", mode='w', bufsize) -==> -pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin - - -(child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize) -==> -p = Popen("cmd", shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdin, child_stdout) = (p.stdin, p.stdout) - - -(child_stdin, - child_stdout, - child_stderr) = os.popen3("cmd", mode, bufsize) -==> -p = Popen("cmd", shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) -(child_stdin, - child_stdout, - child_stderr) = (p.stdin, p.stdout, p.stderr) - - -(child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode, - bufsize) -==> -p = Popen("cmd", shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) -(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) - -On Unix, os.popen2, os.popen3 and os.popen4 also accept a sequence as -the command to execute, in which case arguments will be passed -directly to the program without shell intervention. This usage can be -replaced as follows: - -(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode, - bufsize) -==> -p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE) -(child_stdin, child_stdout) = (p.stdin, p.stdout) - -Return code handling translates as follows: - -pipe = os.popen("cmd", 'w') -... -rc = pipe.close() -if rc is not None and rc % 256: - print "There were some errors" -==> -process = Popen("cmd", 'w', shell=True, stdin=PIPE) -... -process.stdin.close() -if process.wait() != 0: - print "There were some errors" - - -Replacing popen2.* ------------------- -(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) -==> -p = Popen(["somestring"], shell=True, bufsize=bufsize - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdout, child_stdin) = (p.stdout, p.stdin) - -On Unix, popen2 also accepts a sequence as the command to execute, in -which case arguments will be passed directly to the program without -shell intervention. This usage can be replaced as follows: - -(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, - mode) -==> -p = Popen(["mycmd", "myarg"], bufsize=bufsize, - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdout, child_stdin) = (p.stdout, p.stdin) - -The popen2.Popen3 and popen2.Popen4 basically works as subprocess.Popen, -except that: - -* subprocess.Popen raises an exception if the execution fails -* the capturestderr argument is replaced with the stderr argument. -* stdin=PIPE and stdout=PIPE must be specified. -* popen2 closes all filedescriptors by default, but you have to specify - close_fds=True with subprocess.Popen. +Constants +--------- +PIPE: Special value that indicates a pipe should be created +STDOUT: Special value that indicates that stderr should go to stdout """ import sys @@ -400,8 +44,9 @@ class CalledProcessError(Exception): """This exception is raised when a process run by check_call() or check_output() returns a non-zero exit status. - The exit status will be stored in the returncode attribute; - check_output() will also store the output in the output attribute. + + Attributes: + cmd, returncode, output """ def __init__(self, returncode, cmd, output=None): self.returncode = returncode @@ -646,6 +291,40 @@ class Popen(object): + """ Execute a child program in a new process. + + For a complete description of the arguments see the Python documentation. + + Arguments: + args: A string, or a sequence of program arguments. + + bufsize: supplied as the buffering argument to the open() function when + creating the stdin/stdout/stderr pipe file objects + + executable: A replacement program to execute. + + stdin, stdout and stderr: These specify the executed programs' standard + input, standard output and standard error file handles, respectively. + + preexec_fn: (POSIX only) An object to be called in the child process + just before the child is executed. + + close_fds: Controls closing or inheriting of file descriptors. + + shell: If true, the command will be executed through the shell. + + cwd: Sets the current directory before the child is executed. + + env: Defines the environment variables for the new process. + + universal_newlines: If true, use universal line endings for file + objects stdin, stdout and stderr. + + startupinfo and creationflags (Windows only) + + Attributes: + stdin, stdout, stderr, pid, returncode + """ _child_created = False # Set here since __del__ checks it def __init__(self, args, bufsize=0, executable=None, @@ -801,6 +480,8 @@ def poll(self): + """Check if child process has terminated. Set and return returncode + attribute.""" return self._internal_poll() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -940,6 +940,7 @@ Andrii V. Mishkovskyi Dom Mitchell Dustin J. Mitchell +Tim Mitchell Zubin Mithra Florian Mladitsch Doug Moen -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 21:43:43 2016 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Oct 2016 01:43:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI1MDAy?= =?utf-8?q?=3A_Back_out_asyncore/asynchat_deprecation=2E?= Message-ID: <20161026014343.9679.11475.6AE714E0@psf.io> https://hg.python.org/cpython/rev/6eb3312a9a16 changeset: 104733:6eb3312a9a16 branch: 3.6 parent: 104730:8358c68579e9 user: Guido van Rossum date: Tue Oct 25 18:42:51 2016 -0700 summary: Issue #25002: Back out asyncore/asynchat deprecation. files: Lib/asynchat.py | 5 ----- Lib/asyncore.py | 4 ---- 2 files changed, 0 insertions(+), 9 deletions(-) diff --git a/Lib/asynchat.py b/Lib/asynchat.py --- a/Lib/asynchat.py +++ b/Lib/asynchat.py @@ -46,13 +46,8 @@ you - by calling your self.found_terminator() method. """ import asyncore -import warnings - from collections import deque -warnings.warn( - 'asynchat module is deprecated in 3.6. Use asyncio instead.', - PendingDeprecationWarning, stacklevel=2) class async_chat(asyncore.dispatcher): """This is an abstract class. You must derive from this class, and add diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -60,10 +60,6 @@ _DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF}) -warnings.warn( - 'asyncore module is deprecated in 3.6. Use asyncio instead.', - PendingDeprecationWarning, stacklevel=2) - try: socket_map except NameError: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 21:43:43 2016 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Oct 2016 01:43:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2325002=3A_Back_out_asyncore/asynchat_deprecation?= =?utf-8?b?LiAoMy42LT4zLjcp?= Message-ID: <20161026014343.66891.50381.E18A8352@psf.io> https://hg.python.org/cpython/rev/2879185bc511 changeset: 104734:2879185bc511 parent: 104731:0dd8b3f133f9 parent: 104733:6eb3312a9a16 user: Guido van Rossum date: Tue Oct 25 18:43:21 2016 -0700 summary: Issue #25002: Back out asyncore/asynchat deprecation. (3.6->3.7) files: Lib/asynchat.py | 5 ----- Lib/asyncore.py | 4 ---- 2 files changed, 0 insertions(+), 9 deletions(-) diff --git a/Lib/asynchat.py b/Lib/asynchat.py --- a/Lib/asynchat.py +++ b/Lib/asynchat.py @@ -46,13 +46,8 @@ you - by calling your self.found_terminator() method. """ import asyncore -import warnings - from collections import deque -warnings.warn( - 'asynchat module is deprecated in 3.6. Use asyncio instead.', - PendingDeprecationWarning, stacklevel=2) class async_chat(asyncore.dispatcher): """This is an abstract class. You must derive from this class, and add diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -60,10 +60,6 @@ _DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF}) -warnings.warn( - 'asyncore module is deprecated in 3.6. Use asyncio instead.', - PendingDeprecationWarning, stacklevel=2) - try: socket_map except NameError: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 22:37:02 2016 From: python-checkins at python.org (zach.ware) Date: Wed, 26 Oct 2016 02:37:02 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5?= Message-ID: <20161026023702.12034.25991.BA6348D5@psf.io> https://hg.python.org/cpython/rev/c647759eb650 changeset: 104736:c647759eb650 branch: 3.6 parent: 104733:6eb3312a9a16 parent: 104735:5d1934c27137 user: Zachary Ware date: Tue Oct 25 21:36:13 2016 -0500 summary: Merge from 3.5 files: Doc/library/venv.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -24,7 +24,7 @@ See :pep:`405` for more information about Python virtual environments. .. note:: - The `pyvenv` script has been deprecated as of Python 3.6 in favor of using + The ``pyvenv`` script has been deprecated as of Python 3.6 in favor of using ``python3 -m venv`` to help prevent any potential confusion as to which Python interpreter a virtual environment will be based on. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 22:37:02 2016 From: python-checkins at python.org (zach.ware) Date: Wed, 26 Oct 2016 02:37:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fix_default_ro?= =?utf-8?q?le_usage?= Message-ID: <20161026023701.109702.31897.16D17D13@psf.io> https://hg.python.org/cpython/rev/5d1934c27137 changeset: 104735:5d1934c27137 branch: 3.5 parent: 104729:720865fa61a4 user: Zachary Ware date: Tue Oct 25 21:35:22 2016 -0500 summary: Fix default role usage files: Doc/library/venv.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -24,7 +24,7 @@ See :pep:`405` for more information about Python virtual environments. .. note:: - The `pyvenv` script has been deprecated as of Python 3.6 in favor of using + The ``pyvenv`` script has been deprecated as of Python 3.6 in favor of using ``python3 -m venv`` to help prevent any potential confusion as to which Python interpreter a virtual environment will be based on. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 22:37:02 2016 From: python-checkins at python.org (zach.ware) Date: Wed, 26 Oct 2016 02:37:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_from_3=2E6?= Message-ID: <20161026023702.109571.27439.E916E217@psf.io> https://hg.python.org/cpython/rev/bb1b70791743 changeset: 104737:bb1b70791743 parent: 104734:2879185bc511 parent: 104736:c647759eb650 user: Zachary Ware date: Tue Oct 25 21:36:48 2016 -0500 summary: Merge from 3.6 files: Doc/library/venv.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -24,7 +24,7 @@ See :pep:`405` for more information about Python virtual environments. .. note:: - The `pyvenv` script has been deprecated as of Python 3.6 in favor of using + The ``pyvenv`` script has been deprecated as of Python 3.6 in favor of using ``python3 -m venv`` to help prevent any potential confusion as to which Python interpreter a virtual environment will be based on. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 22:49:33 2016 From: python-checkins at python.org (zach.ware) Date: Wed, 26 Oct 2016 02:49:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Ignore_harmles?= =?utf-8?q?s_suspicious_markup?= Message-ID: <20161026024933.11928.70702.CB881291@psf.io> https://hg.python.org/cpython/rev/4ddb89661a7f changeset: 104738:4ddb89661a7f branch: 3.6 parent: 104736:c647759eb650 user: Zachary Ware date: Tue Oct 25 21:43:41 2016 -0500 summary: Ignore harmless suspicious markup files: Doc/tools/susp-ignored.csv | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -325,3 +325,4 @@ whatsnew/changelog,,:version,import sys; I = version[:version.index(' ')] whatsnew/changelog,,:gz,": TarFile opened with external fileobj and ""w:gz"" mode didn't" whatsnew/changelog,,::,": Use ""127.0.0.1"" or ""::1"" instead of ""localhost"" as much as" +whatsnew/changelog,,`,"for readability (was ""`"")." -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 22:49:34 2016 From: python-checkins at python.org (zach.ware) Date: Wed, 26 Oct 2016 02:49:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_from_3=2E6?= Message-ID: <20161026024933.66800.5805.B2A6E45E@psf.io> https://hg.python.org/cpython/rev/a9c64aeadb6c changeset: 104739:a9c64aeadb6c parent: 104737:bb1b70791743 parent: 104738:4ddb89661a7f user: Zachary Ware date: Tue Oct 25 21:48:29 2016 -0500 summary: Merge from 3.6 files: Doc/tools/susp-ignored.csv | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -325,3 +325,4 @@ whatsnew/changelog,,:version,import sys; I = version[:version.index(' ')] whatsnew/changelog,,:gz,": TarFile opened with external fileobj and ""w:gz"" mode didn't" whatsnew/changelog,,::,": Use ""127.0.0.1"" or ""::1"" instead of ""localhost"" as much as" +whatsnew/changelog,,`,"for readability (was ""`"")." -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Oct 25 22:49:34 2016 From: python-checkins at python.org (zach.ware) Date: Wed, 26 Oct 2016 02:49:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_unused_suspicious_r?= =?utf-8?q?ules?= Message-ID: <20161026024934.109609.6212.650ADAEF@psf.io> https://hg.python.org/cpython/rev/849826a900d2 changeset: 104740:849826a900d2 user: Zachary Ware date: Tue Oct 25 21:49:19 2016 -0500 summary: Remove unused suspicious rules files: Doc/tools/susp-ignored.csv | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -323,6 +323,4 @@ whatsnew/3.5,,:root,ERROR:root:exception whatsnew/3.5,,:exception,ERROR:root:exception whatsnew/changelog,,:version,import sys; I = version[:version.index(' ')] -whatsnew/changelog,,:gz,": TarFile opened with external fileobj and ""w:gz"" mode didn't" -whatsnew/changelog,,::,": Use ""127.0.0.1"" or ""::1"" instead of ""localhost"" as much as" whatsnew/changelog,,`,"for readability (was ""`"")." -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Wed Oct 26 14:50:10 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 26 Oct 2016 19:50:10 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python 2.7 2016-10-26 Message-ID: <16f200b4-0c54-4e2d-b15f-93932496a09c@irsmsx103.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-26 02:47:59 +0000 commit: 5a1edf5701f1 previous commit: f57078cf5f13 revision date: 2016-10-26 00:44:31 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.13% 1.13% 5.14% 4.41% :-) pybench 0.12% -0.18% 5.78% 3.95% :-( regex_v8 0.64% -0.04% -2.10% 10.99% :-) nbody 0.07% 0.06% 7.95% 2.81% :-) json_dump_v2 0.30% -0.00% 2.65% 10.96% :-| normal_startup 0.73% -0.12% -0.27% 2.04% :-| ssbench 0.24% -0.07% 1.96% 2.01% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-2-7-2016-10-26/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Wed Oct 26 14:50:48 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Wed, 26 Oct 2016 19:50:48 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-26 Message-ID: <78e434d0-642f-44b8-ac37-c70454e41e88@irsmsx103.ger.corp.intel.com> Results for project Python default, build date 2016-10-26 02:01:40 +0000 commit: 2879185bc511 previous commit: 5b33829badcc revision date: 2016-10-26 01:43:21 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.21% -1.38% 4.05% 16.07% :-) pybench 0.11% -0.21% 5.31% 4.99% :-) regex_v8 3.89% 2.29% -1.70% 4.11% :-) nbody 0.10% 1.61% 3.64% 4.96% :-( json_dump_v2 0.24% -0.97% -10.36% 16.04% :-| normal_startup 0.61% -0.08% 0.21% 5.92% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-26/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Thu Oct 27 06:30:19 2016 From: python-checkins at python.org (inada.naoki) Date: Thu, 27 Oct 2016 10:30:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328509=3A_dict=2Eupdate=28=29_no_longer_allocate?= =?utf-8?q?_unnecessary_large_memory?= Message-ID: <20161027103018.62019.95473.68703613@psf.io> https://hg.python.org/cpython/rev/deb3e5857d8c changeset: 104742:deb3e5857d8c parent: 104740:849826a900d2 parent: 104741:8c2615decd2e user: INADA Naoki date: Thu Oct 27 19:30:10 2016 +0900 summary: Issue #28509: dict.update() no longer allocate unnecessary large memory files: Misc/NEWS | 2 ++ Objects/dictobject.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28509: dict.update() no longer allocate unnecessary large memory. + - Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug build. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2407,9 +2407,11 @@ * incrementally resizing as we insert new items. Expect * that there will be no (or few) overlapping keys. */ - if (mp->ma_keys->dk_usable * 3 < other->ma_used * 2) - if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) + if (USABLE_FRACTION(mp->ma_keys->dk_size) < other->ma_used) { + if (dictresize(mp, ESTIMATE_SIZE(mp->ma_used + other->ma_used))) { return -1; + } + } ep0 = DK_ENTRIES(other->ma_keys); for (i = 0, n = other->ma_keys->dk_nentries; i < n; i++) { PyObject *key, *value; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 06:30:18 2016 From: python-checkins at python.org (inada.naoki) Date: Thu, 27 Oct 2016 10:30:18 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTA5?= =?utf-8?q?=3A_dict=2Eupdate=28=29_no_longer_allocate_unnecessary_large_me?= =?utf-8?q?mory?= Message-ID: <20161027103018.12110.77074.3D0FB58F@psf.io> https://hg.python.org/cpython/rev/8c2615decd2e changeset: 104741:8c2615decd2e branch: 3.6 parent: 104738:4ddb89661a7f user: INADA Naoki date: Thu Oct 27 19:26:50 2016 +0900 summary: Issue #28509: dict.update() no longer allocate unnecessary large memory files: Misc/NEWS | 2 ++ Objects/dictobject.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #28509: dict.update() no longer allocate unnecessary large memory. + - Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug build. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2406,9 +2406,11 @@ * incrementally resizing as we insert new items. Expect * that there will be no (or few) overlapping keys. */ - if (mp->ma_keys->dk_usable * 3 < other->ma_used * 2) - if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) + if (USABLE_FRACTION(mp->ma_keys->dk_size) < other->ma_used) { + if (dictresize(mp, ESTIMATE_SIZE(mp->ma_used + other->ma_used))) { return -1; + } + } ep0 = DK_ENTRIES(other->ma_keys); for (i = 0, n = other->ma_keys->dk_nentries; i < n; i++) { PyObject *key, *value; -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Thu Oct 27 09:11:16 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 27 Oct 2016 14:11:16 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python 2.7 2016-10-27 Message-ID: No new revisions. Here are the previous results: Results for project Python 2.7, build date 2016-10-27 02:49:11 +0000 commit: 5a1edf5701f1 previous commit: f57078cf5f13 revision date: 2016-10-26 00:44:31 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.13% 1.13% 5.14% 4.41% :-) pybench 0.12% -0.18% 5.78% 3.95% :-( regex_v8 0.64% -0.04% -2.10% 10.99% :-) nbody 0.07% 0.06% 7.95% 2.81% :-) json_dump_v2 0.30% -0.00% 2.65% 10.96% :-| normal_startup 0.73% -0.12% -0.27% 2.04% :-| ssbench 0.24% -0.07% 1.96% 2.01% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-2-7-2016-10-27/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Thu Oct 27 09:11:40 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Thu, 27 Oct 2016 14:11:40 +0100 Subject: [Python-checkins] GOOD Benchmark Results for Python Default 2016-10-27 Message-ID: <37ddccb0-57c2-4183-91b7-727bdfe908da@irsmsx151.ger.corp.intel.com> Results for project Python default, build date 2016-10-27 02:02:15 +0000 commit: 849826a900d2 previous commit: 2879185bc511 revision date: 2016-10-26 02:49:19 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.21% 1.12% 5.13% 17.11% :-) pybench 0.13% -0.00% 5.31% 3.98% :-| regex_v8 3.88% 0.02% -1.68% 3.81% :-) nbody 0.11% 0.01% 3.65% 3.83% :-( json_dump_v2 0.32% -0.01% -10.37% 13.25% :-| normal_startup 0.88% 0.24% 0.89% 6.49% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/good-benchmark-results-for-python-default-2016-10-27/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Thu Oct 27 12:33:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 16:33:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NTI2?= =?utf-8?q?=3A_Use_PyUnicode=5FAsEncodedString=28=29_instead_of?= Message-ID: <20161027163345.27413.86201.8345E589@psf.io> https://hg.python.org/cpython/rev/bea48e72cae5 changeset: 104743:bea48e72cae5 branch: 3.5 parent: 104735:5d1934c27137 user: Serhiy Storchaka date: Thu Oct 27 19:31:49 2016 +0300 summary: Issue #28526: Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject() in _curese to ensure that the result is a bytes object. files: Modules/_cursesmodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -230,7 +230,7 @@ encoding = win->encoding; else encoding = screen_encoding; - bytes = PyUnicode_AsEncodedObject(obj, encoding, NULL); + bytes = PyUnicode_AsEncodedString(obj, encoding, NULL); if (bytes == NULL) return 0; if (PyBytes_GET_SIZE(bytes) == 1) @@ -352,7 +352,7 @@ return 2; #else assert (wstr == NULL); - *bytes = PyUnicode_AsEncodedObject(obj, win->encoding, NULL); + *bytes = PyUnicode_AsEncodedString(obj, win->encoding, NULL); if (*bytes == NULL) return 0; return 1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 12:33:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 16:33:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328526=3A_Use_PyUnicode=5FAsEncodedString=28=29_?= =?utf-8?q?instead_of?= Message-ID: <20161027163345.27140.78903.6367FE50@psf.io> https://hg.python.org/cpython/rev/a6548e230ed6 changeset: 104745:a6548e230ed6 parent: 104742:deb3e5857d8c parent: 104744:fe9f361f3751 user: Serhiy Storchaka date: Thu Oct 27 19:33:22 2016 +0300 summary: Issue #28526: Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject() in _curese to ensure that the result is a bytes object. files: Modules/_cursesmodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -230,7 +230,7 @@ encoding = win->encoding; else encoding = screen_encoding; - bytes = PyUnicode_AsEncodedObject(obj, encoding, NULL); + bytes = PyUnicode_AsEncodedString(obj, encoding, NULL); if (bytes == NULL) return 0; if (PyBytes_GET_SIZE(bytes) == 1) @@ -352,7 +352,7 @@ return 2; #else assert (wstr == NULL); - *bytes = PyUnicode_AsEncodedObject(obj, win->encoding, NULL); + *bytes = PyUnicode_AsEncodedString(obj, win->encoding, NULL); if (*bytes == NULL) return 0; return 1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 12:33:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 16:33:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328526=3A_Use_PyUnicode=5FAsEncodedString=28=29_instea?= =?utf-8?q?d_of?= Message-ID: <20161027163345.12034.20248.70AF2FAA@psf.io> https://hg.python.org/cpython/rev/fe9f361f3751 changeset: 104744:fe9f361f3751 branch: 3.6 parent: 104741:8c2615decd2e parent: 104743:bea48e72cae5 user: Serhiy Storchaka date: Thu Oct 27 19:33:05 2016 +0300 summary: Issue #28526: Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject() in _curese to ensure that the result is a bytes object. files: Modules/_cursesmodule.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -230,7 +230,7 @@ encoding = win->encoding; else encoding = screen_encoding; - bytes = PyUnicode_AsEncodedObject(obj, encoding, NULL); + bytes = PyUnicode_AsEncodedString(obj, encoding, NULL); if (bytes == NULL) return 0; if (PyBytes_GET_SIZE(bytes) == 1) @@ -352,7 +352,7 @@ return 2; #else assert (wstr == NULL); - *bytes = PyUnicode_AsEncodedObject(obj, win->encoding, NULL); + *bytes = PyUnicode_AsEncodedString(obj, win->encoding, NULL); if (*bytes == NULL) return 0; return 1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 14:08:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 18:08:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328426=3A_Deprecated_undocumented_functions_PyUn?= =?utf-8?q?icode=5FAsEncodedObject=28=29=2C?= Message-ID: <20161027180816.27231.14682.6FFAB42B@psf.io> https://hg.python.org/cpython/rev/50c28727d91c changeset: 104747:50c28727d91c parent: 104745:a6548e230ed6 parent: 104746:15a494886c5a user: Serhiy Storchaka date: Thu Oct 27 21:08:00 2016 +0300 summary: Issue #28426: Deprecated undocumented functions PyUnicode_AsEncodedObject(), PyUnicode_AsDecodedObject(), PyUnicode_AsDecodedUnicode() and PyUnicode_AsEncodedUnicode(). files: Doc/whatsnew/3.6.rst | 5 +++- Include/unicodeobject.h | 33 +++++++++++++++++++++------- Misc/NEWS | 7 ++++++ Objects/unicodeobject.c | 21 ++++++++++++++++++ 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -1231,7 +1231,10 @@ Deprecated functions and types of the C API ------------------------------------------- -* None yet. +* Undocumented functions :c:func:`PyUnicode_AsEncodedObject`, + :c:func:`PyUnicode_AsDecodedObject`, :c:func:`PyUnicode_AsEncodedUnicode` + and :c:func:`PyUnicode_AsDecodedUnicode` are deprecated now. + Use :ref:`generic codec based API ` instead. Deprecated features diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1171,22 +1171,30 @@ ); /* Decode a Unicode object unicode and return the result as Python - object. */ + object. + + This API is DEPRECATED. The only supported standard encoding is rot13. + Use PyCodec_Decode() to decode with rot13 and non-standard codecs + that decode from str. */ PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedObject( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Decode a Unicode object unicode and return the result as Unicode - object. */ + object. + + This API is DEPRECATED. The only supported standard encoding is rot13. + Use PyCodec_Decode() to decode with rot13 and non-standard codecs + that decode from str to str. */ PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedUnicode( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Encodes a Py_UNICODE buffer of the given size and returns a Python string object. */ @@ -1201,13 +1209,18 @@ #endif /* Encodes a Unicode object and returns the result as Python - object. */ + object. + + This API is DEPRECATED. It is superceeded by PyUnicode_AsEncodedString() + since all standard encodings (except rot13) encode str to bytes. + Use PyCodec_Encode() for encoding with rot13 and non-standard codecs + that encode form str to non-bytes. */ PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedObject( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Encodes a Unicode object and returns the result as Python string object. */ @@ -1219,13 +1232,17 @@ ); /* Encodes a Unicode object and returns the result as Unicode - object. */ + object. + + This API is DEPRECATED. The only supported standard encodings is rot13. + Use PyCodec_Encode() to encode with rot13 and non-standard codecs + that encode from str to str. */ PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedUnicode( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Build an encoding map. */ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -345,6 +345,13 @@ - Issue #28138: Windows ._pth file should allow import site +C API +----- + +- Issue #28426: Deprecated undocumented functions PyUnicode_AsEncodedObject(), + PyUnicode_AsDecodedObject(), PyUnicode_AsDecodedUnicode() and + PyUnicode_AsEncodedUnicode(). + Build ----- diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3237,6 +3237,11 @@ return NULL; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsDecodedObject() is deprecated; " + "use PyCodec_Decode() to decode from str", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -3256,6 +3261,11 @@ goto onError; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsDecodedUnicode() is deprecated; " + "use PyCodec_Decode() to decode from str to str", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -3306,6 +3316,12 @@ goto onError; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsEncodedObject() is deprecated; " + "use PyUnicode_AsEncodedString() to encode from str to bytes " + "or PyCodec_Encode() for generic encoding", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -3628,6 +3644,11 @@ goto onError; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsEncodedUnicode() is deprecated; " + "use PyCodec_Encode() to encode from str to str", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 14:08:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 18:08:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NDI2?= =?utf-8?q?=3A_Deprecated_undocumented_functions_PyUnicode=5FAsEncodedObje?= =?utf-8?b?Y3QoKSw=?= Message-ID: <20161027180816.18045.32623.5FE67EE3@psf.io> https://hg.python.org/cpython/rev/15a494886c5a changeset: 104746:15a494886c5a branch: 3.6 parent: 104744:fe9f361f3751 user: Serhiy Storchaka date: Thu Oct 27 21:05:49 2016 +0300 summary: Issue #28426: Deprecated undocumented functions PyUnicode_AsEncodedObject(), PyUnicode_AsDecodedObject(), PyUnicode_AsDecodedUnicode() and PyUnicode_AsEncodedUnicode(). files: Doc/whatsnew/3.6.rst | 5 +++- Include/unicodeobject.h | 33 +++++++++++++++++++++------- Misc/NEWS | 7 ++++++ Objects/unicodeobject.c | 21 ++++++++++++++++++ 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -1230,7 +1230,10 @@ Deprecated functions and types of the C API ------------------------------------------- -* None yet. +* Undocumented functions :c:func:`PyUnicode_AsEncodedObject`, + :c:func:`PyUnicode_AsDecodedObject`, :c:func:`PyUnicode_AsEncodedUnicode` + and :c:func:`PyUnicode_AsDecodedUnicode` are deprecated now. + Use :ref:`generic codec based API ` instead. Deprecated features diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1171,22 +1171,30 @@ ); /* Decode a Unicode object unicode and return the result as Python - object. */ + object. + + This API is DEPRECATED. The only supported standard encoding is rot13. + Use PyCodec_Decode() to decode with rot13 and non-standard codecs + that decode from str. */ PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedObject( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Decode a Unicode object unicode and return the result as Unicode - object. */ + object. + + This API is DEPRECATED. The only supported standard encoding is rot13. + Use PyCodec_Decode() to decode with rot13 and non-standard codecs + that decode from str to str. */ PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedUnicode( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Encodes a Py_UNICODE buffer of the given size and returns a Python string object. */ @@ -1201,13 +1209,18 @@ #endif /* Encodes a Unicode object and returns the result as Python - object. */ + object. + + This API is DEPRECATED. It is superceeded by PyUnicode_AsEncodedString() + since all standard encodings (except rot13) encode str to bytes. + Use PyCodec_Encode() for encoding with rot13 and non-standard codecs + that encode form str to non-bytes. */ PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedObject( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Encodes a Unicode object and returns the result as Python string object. */ @@ -1219,13 +1232,17 @@ ); /* Encodes a Unicode object and returns the result as Unicode - object. */ + object. + + This API is DEPRECATED. The only supported standard encodings is rot13. + Use PyCodec_Encode() to encode with rot13 and non-standard codecs + that encode from str to str. */ PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedUnicode( PyObject *unicode, /* Unicode object */ const char *encoding, /* encoding */ const char *errors /* error handling */ - ); + ) Py_DEPRECATED(3.6); /* Build an encoding map. */ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -349,6 +349,13 @@ - Issue #28138: Windows ._pth file should allow import site +C API +----- + +- Issue #28426: Deprecated undocumented functions PyUnicode_AsEncodedObject(), + PyUnicode_AsDecodedObject(), PyUnicode_AsDecodedUnicode() and + PyUnicode_AsEncodedUnicode(). + Build ----- diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3241,6 +3241,11 @@ return NULL; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsDecodedObject() is deprecated; " + "use PyCodec_Decode() to decode from str", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -3260,6 +3265,11 @@ goto onError; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsDecodedUnicode() is deprecated; " + "use PyCodec_Decode() to decode from str to str", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -3310,6 +3320,12 @@ goto onError; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsEncodedObject() is deprecated; " + "use PyUnicode_AsEncodedString() to encode from str to bytes " + "or PyCodec_Encode() for generic encoding", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); @@ -3635,6 +3651,11 @@ goto onError; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_AsEncodedUnicode() is deprecated; " + "use PyCodec_Encode() to encode from str to str", 1) < 0) + return NULL; + if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 14:43:16 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 18:43:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4NDk2?= =?utf-8?q?=3A_Mark_up_constants_0=2C_1_and_-1_that_denote_return_values_o?= =?utf-8?q?r?= Message-ID: <20161027184315.81178.37251.49D1B05A@psf.io> https://hg.python.org/cpython/rev/e90fe2209276 changeset: 104748:e90fe2209276 branch: 2.7 parent: 104732:5a1edf5701f1 user: Serhiy Storchaka date: Thu Oct 27 21:41:04 2016 +0300 summary: Issue #28496: Mark up constants 0, 1 and -1 that denote return values or special input values as literal text. files: Doc/c-api/arg.rst | 2 +- Doc/c-api/buffer.rst | 12 ++++---- Doc/c-api/capsule.rst | 10 +++--- Doc/c-api/conversion.rst | 2 +- Doc/c-api/file.rst | 4 +- Doc/c-api/import.rst | 2 +- Doc/c-api/init.rst | 16 ++++++------ Doc/c-api/int.rst | 2 +- Doc/c-api/marshal.rst | 4 +- Doc/c-api/set.rst | 6 ++-- Doc/c-api/slice.rst | 6 ++-- Doc/c-api/structures.rst | 2 +- Doc/c-api/unicode.rst | 36 ++++++++++++++-------------- 13 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -425,7 +425,7 @@ only if its format string contains two or more format units. If the format string is empty, it returns ``None``; if it contains exactly one format unit, it returns whatever object is described by that format unit. To - force it to return a tuple of size 0 or one, parenthesize the format + force it to return a tuple of size ``0`` or one, parenthesize the format string. When memory buffers are passed as parameters to supply data to build diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -74,7 +74,7 @@ .. c:member:: int ndim The number of dimensions the memory represents as a multi-dimensional - array. If it is 0, :c:data:`strides` and :c:data:`suboffsets` must be + array. If it is ``0``, :c:data:`strides` and :c:data:`suboffsets` must be *NULL*. .. c:member:: Py_ssize_t *shape @@ -143,7 +143,7 @@ .. c:function:: int PyObject_CheckBuffer(PyObject *obj) - Return 1 if *obj* supports the buffer interface otherwise 0. + Return ``1`` if *obj* supports the buffer interface otherwise ``0``. .. c:function:: int PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) @@ -164,7 +164,7 @@ :c:data:`Py_buffer` structure is filled in with non-default values and/or raise an error if the object can't support a simpler view of its memory. - 0 is returned on success and -1 on error. + ``0`` is returned on success and ``-1`` on error. The following table gives possible values to the *flags* arguments. @@ -273,9 +273,9 @@ .. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char fortran) - Return 1 if the memory defined by the *view* is C-style (*fortran* is + Return ``1`` if the memory defined by the *view* is C-style (*fortran* is ``'C'``) or Fortran-style (*fortran* is ``'F'``) contiguous or either one - (*fortran* is ``'A'``). Return 0 otherwise. + (*fortran* is ``'A'``). Return ``0`` otherwise. .. c:function:: void PyBuffer_FillContiguousStrides(int ndim, Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t itemsize, char fortran) @@ -289,7 +289,7 @@ Fill in a buffer-info structure, *view*, correctly for an exporter that can only share a contiguous chunk of memory of "unsigned bytes" of the given - length. Return 0 on success and -1 (with raising an error) on error. + length. Return ``0`` on success and ``-1`` (with raising an error) on error. MemoryView objects diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -120,19 +120,19 @@ guaranteed to succeed. Return a nonzero value if the object is valid and matches the name passed in. - Return 0 otherwise. This function will not fail. + Return ``0`` otherwise. This function will not fail. .. c:function:: int PyCapsule_SetContext(PyObject *capsule, void *context) Set the context pointer inside *capsule* to *context*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor) Set the destructor inside *capsule* to *destructor*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetName(PyObject *capsule, const char *name) @@ -140,11 +140,11 @@ outlive the capsule. If the previous *name* stored in the capsule was not *NULL*, no attempt is made to free it. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetPointer(PyObject *capsule, void *pointer) Set the void pointer inside *capsule* to *pointer*. The pointer may not be *NULL*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -126,7 +126,7 @@ *format_code* must be one of ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, ``'G'`` or ``'r'``. For ``'r'``, the supplied *precision* - must be 0 and is ignored. The ``'r'`` format code specifies the + must be ``0`` and is ignored. The ``'r'`` format code specifies the standard :func:`repr` format. *flags* can be zero or more of the values *Py_DTSF_SIGN*, diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -136,7 +136,7 @@ .. c:function:: int PyFile_SetEncoding(PyFileObject *p, const char *enc) - Set the file's encoding for Unicode output to *enc*. Return 1 on success and 0 + Set the file's encoding for Unicode output to *enc*. Return ``1`` on success and ``0`` on failure. .. versionadded:: 2.3 @@ -145,7 +145,7 @@ .. c:function:: int PyFile_SetEncodingAndErrors(PyFileObject *p, const char *enc, *errors) Set the file's encoding for Unicode output to *enc*, and its error - mode to *err*. Return 1 on success and 0 on failure. + mode to *err*. Return ``1`` on success and ``0`` on failure. .. versionadded:: 2.6 diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -66,7 +66,7 @@ .. versionchanged:: 2.6 The function is an alias for :c:func:`PyImport_ImportModuleLevel` with - -1 as level, meaning relative import. + ``-1`` as level, meaning relative import. .. c:function:: PyObject* PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) 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 @@ -43,8 +43,8 @@ .. c:function:: void Py_InitializeEx(int initsigs) - This function works like :c:func:`Py_Initialize` if *initsigs* is 1. If - *initsigs* is 0, it skips initialization registration of signal handlers, which + This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If + *initsigs* is ``0``, it skips initialization registration of signal handlers, which might be useful when Python is embedded. .. versionadded:: 2.4 @@ -295,7 +295,7 @@ .. note:: It is recommended that applications embedding the Python interpreter - for purposes other than executing a single script pass 0 as *updatepath*, + for purposes other than executing a single script pass ``0`` as *updatepath*, and update :data:`sys.path` themselves if desired. See `CVE-2008-5983 `_. @@ -307,13 +307,13 @@ .. versionadded:: 2.6.6 - .. XXX impl. doesn't seem consistent in allowing 0/NULL for the params; + .. XXX impl. doesn't seem consistent in allowing ``0``/``NULL`` for the params; check w/ Guido. .. c:function:: void PySys_SetArgv(int argc, char **argv) - This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set to 1. + This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set to ``1``. .. c:function:: void Py_SetPythonHome(char *home) @@ -917,8 +917,8 @@ .. index:: single: Py_AddPendingCall() Schedule a function to be called from the main interpreter thread. On - success, 0 is returned and *func* is queued for being called in the - main thread. On failure, -1 is returned without setting any exception. + success, ``0`` is returned and *func* is queued for being called in the + main thread. On failure, ``-1`` is returned without setting any exception. When successfully queued, *func* will be *eventually* called from the main interpreter thread with the argument *arg*. It will be called @@ -929,7 +929,7 @@ * with the main thread holding the :term:`global interpreter lock` (*func* can therefore use the full C API). - *func* must return 0 on success, or -1 on failure with an exception + *func* must return ``0`` on success, or ``-1`` on failure with an exception set. *func* won't be interrupted to perform another asynchronous notification recursively, but it can still be interrupted to switch threads if the global interpreter lock is released. diff --git a/Doc/c-api/int.rst b/Doc/c-api/int.rst --- a/Doc/c-api/int.rst +++ b/Doc/c-api/int.rst @@ -88,7 +88,7 @@ Will first attempt to cast the object to a :c:type:`PyIntObject`, if it is not already one, and then return its value. If there is an error, ``-1`` is returned, and the caller should check ``PyErr_Occurred()`` to find out whether - there was an error, or whether the value just happened to be -1. + there was an error, or whether the value just happened to be ``-1``. .. c:function:: long PyInt_AS_LONG(PyObject *io) diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -13,8 +13,8 @@ Numeric values are stored with the least significant byte first. -The module supports two versions of the data format: version 0 is the -historical version, version 1 (new in Python 2.4) shares interned strings in +The module supports two versions of the data format: version ``0`` is the +historical version, version ``1`` (new in Python 2.4) shares interned strings in the file, and upon unmarshalling. Version 2 (new in Python 2.5) uses a binary format for floating point numbers. *Py_MARSHAL_VERSION* indicates the current file format (currently 2). diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -128,7 +128,7 @@ .. c:function:: int PySet_Contains(PyObject *anyset, PyObject *key) - Return 1 if found, 0 if not found, and -1 if an error is encountered. Unlike + Return ``1`` if found, ``0`` if not found, and ``-1`` if an error is encountered. Unlike the Python :meth:`__contains__` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise a :exc:`TypeError` if the *key* is unhashable. Raise :exc:`PyExc_SystemError` if *anyset* is not a @@ -138,7 +138,7 @@ .. c:function:: int PySet_Add(PyObject *set, PyObject *key) Add *key* to a :class:`set` instance. Does not apply to :class:`frozenset` - instances. Return 0 on success or -1 on failure. Raise a :exc:`TypeError` if + instances. Return ``0`` on success or ``-1`` on failure. Raise a :exc:`TypeError` if the *key* is unhashable. Raise a :exc:`MemoryError` if there is no room to grow. Raise a :exc:`SystemError` if *set* is not an instance of :class:`set` or its subtype. @@ -154,7 +154,7 @@ .. c:function:: int PySet_Discard(PyObject *set, PyObject *key) - Return 1 if found and removed, 0 if not found (no action taken), and -1 if an + Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard` method, this function does not automatically convert unhashable sets into diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -34,9 +34,9 @@ assuming a sequence of length *length*. Treats indices greater than *length* as errors. - Returns 0 on success and -1 on error with no exception set (unless one of + Returns ``0`` on success and ``-1`` on error with no exception set (unless one of the indices was not :const:`None` and failed to be converted to an integer, - in which case -1 is returned with an exception set). + in which case ``-1`` is returned with an exception set). You probably do not want to use this function. If you want to use slice objects in versions of Python prior to 2.3, you would probably do well to @@ -57,7 +57,7 @@ of bounds indices are clipped in a manner consistent with the handling of normal slices. - Returns 0 on success and -1 on error with exception set. + Returns ``0`` on success and ``-1`` on error with exception set. .. versionadded:: 2.3 diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -314,7 +314,7 @@ handles use of the :keyword:`del` statement on that attribute more correctly than :c:macro:`T_OBJECT`. - :attr:`flags` can be 0 for write and read access or :c:macro:`READONLY` for + :attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for read-only access. Using :c:macro:`T_STRING` for :attr:`type` implies :c:macro:`READONLY`. Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX` members can be deleted. (They are set to *NULL*). 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 @@ -116,52 +116,52 @@ .. c:function:: int Py_UNICODE_ISSPACE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a whitespace character. + Return ``1`` or ``0`` depending on whether *ch* is a whitespace character. .. c:function:: int Py_UNICODE_ISLOWER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a lowercase character. + Return ``1`` or ``0`` depending on whether *ch* is a lowercase character. .. c:function:: int Py_UNICODE_ISUPPER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an uppercase character. + Return ``1`` or ``0`` depending on whether *ch* is an uppercase character. .. c:function:: int Py_UNICODE_ISTITLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a titlecase character. + Return ``1`` or ``0`` depending on whether *ch* is a titlecase character. .. c:function:: int Py_UNICODE_ISLINEBREAK(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a linebreak character. + Return ``1`` or ``0`` depending on whether *ch* is a linebreak character. .. c:function:: int Py_UNICODE_ISDECIMAL(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a decimal character. + Return ``1`` or ``0`` depending on whether *ch* is a decimal character. .. c:function:: int Py_UNICODE_ISDIGIT(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a digit character. + Return ``1`` or ``0`` depending on whether *ch* is a digit character. .. c:function:: int Py_UNICODE_ISNUMERIC(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a numeric character. + Return ``1`` or ``0`` depending on whether *ch* is a numeric character. .. c:function:: int Py_UNICODE_ISALPHA(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphabetic character. + Return ``1`` or ``0`` depending on whether *ch* is an alphabetic character. .. c:function:: int Py_UNICODE_ISALNUM(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphanumeric character. + Return ``1`` or ``0`` depending on whether *ch* is an alphanumeric character. These APIs can be used for fast direct character conversions: @@ -393,7 +393,7 @@ Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing 0-termination character). Return the number of :c:type:`wchar_t` characters - copied or -1 in case of an error. Note that the resulting :c:type:`wchar_t` + copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t` string may or may not be 0-terminated. It is the responsibility of the caller to make sure that the :c:type:`wchar_t` string is 0-terminated in case this is required by the application. Also, note that the :c:type:`wchar_t*` string @@ -1009,7 +1009,7 @@ .. c:function:: PyObject* PyUnicode_Splitlines(PyObject *s, int keepend) Split a Unicode string at line breaks, returning a list of Unicode strings. - CRLF is considered to be one line break. If *keepend* is 0, the Line break + CRLF is considered to be one line break. If *keepend* is ``0``, the Line break characters are not included in the resulting strings. @@ -1037,9 +1037,9 @@ .. c:function:: Py_ssize_t 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 - (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), - 0 otherwise. Return ``-1`` if an error occurred. + 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. .. versionchanged:: 2.5 This function used an :c:type:`int` type for *start* and *end*. This @@ -1050,7 +1050,7 @@ .. 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 - *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a + *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 occurred and an exception has been set. @@ -1075,7 +1075,7 @@ .. c:function:: PyObject* PyUnicode_Replace(PyObject *str, PyObject *substr, PyObject *replstr, Py_ssize_t maxcount) Replace at most *maxcount* occurrences of *substr* in *str* with *replstr* and - return the resulting Unicode object. *maxcount* == -1 means replace all + return the resulting Unicode object. *maxcount* == ``-1`` means replace all occurrences. .. versionchanged:: 2.5 @@ -1085,7 +1085,7 @@ .. c:function:: int PyUnicode_Compare(PyObject *left, PyObject *right) - Compare two strings and return -1, 0, 1 for less than, equal, and greater than, + Compare two strings and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 14:43:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 18:43:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328496=3A_Mark_up_constants_0=2C_1_and_-1_that_denote_?= =?utf-8?q?return_values_or?= Message-ID: <20161027184316.62506.48249.1BADE898@psf.io> https://hg.python.org/cpython/rev/de00be368f0b changeset: 104750:de00be368f0b branch: 3.6 parent: 104746:15a494886c5a parent: 104749:04065efd7747 user: Serhiy Storchaka date: Thu Oct 27 21:42:15 2016 +0300 summary: Issue #28496: Mark up constants 0, 1 and -1 that denote return values or special input values as literal text. files: Doc/c-api/arg.rst | 2 +- Doc/c-api/buffer.rst | 12 +++--- Doc/c-api/capsule.rst | 10 ++-- Doc/c-api/import.rst | 4 +- Doc/c-api/init.rst | 24 +++++++------- Doc/c-api/long.rst | 4 +- Doc/c-api/number.rst | 2 +- Doc/c-api/set.rst | 8 ++-- Doc/c-api/slice.rst | 6 +- Doc/c-api/structures.rst | 2 +- Doc/c-api/typeobj.rst | 6 +- Doc/c-api/unicode.rst | 48 ++++++++++++++-------------- 12 files changed, 64 insertions(+), 64 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -338,7 +338,7 @@ ``p`` (:class:`bool`) [int] Tests the value passed in for truth (a boolean **p**\ redicate) and converts the result to its equivalent C true/false integer value. - Sets the int to 1 if the expression was true and 0 if it was false. + Sets the int to ``1`` if the expression was true and ``0`` if it was false. This accepts any valid Python value. See :ref:`truth` for more information about how Python tests values for truth. diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -156,7 +156,7 @@ .. c:member:: int ndim The number of dimensions the memory represents as an n-dimensional array. - If it is 0, :c:member:`~Py_buffer.buf` points to a single item representing + If it is ``0``, :c:member:`~Py_buffer.buf` points to a single item representing a scalar. In this case, :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides` and :c:member:`~Py_buffer.suboffsets` MUST be *NULL*. @@ -427,7 +427,7 @@ .. c:function:: int PyObject_CheckBuffer(PyObject *obj) - Return 1 if *obj* supports the buffer interface otherwise 0. When 1 is + Return ``1`` if *obj* supports the buffer interface otherwise ``0``. When ``1`` is returned, it doesn't guarantee that :c:func:`PyObject_GetBuffer` will succeed. @@ -437,7 +437,7 @@ Send a request to *exporter* to fill in *view* as specified by *flags*. If the exporter cannot provide a buffer of the exact type, it MUST raise :c:data:`PyExc_BufferError`, set :c:member:`view->obj` to *NULL* and - return -1. + return ``-1``. On success, fill in *view*, set :c:member:`view->obj` to a new reference to *exporter* and return 0. In the case of chained buffer providers @@ -468,9 +468,9 @@ .. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char order) - Return 1 if the memory defined by the *view* is C-style (*order* is + Return ``1`` if the memory defined by the *view* is C-style (*order* is ``'C'``) or Fortran-style (*order* is ``'F'``) :term:`contiguous` or either one - (*order* is ``'A'``). Return 0 otherwise. + (*order* is ``'A'``). Return ``0`` otherwise. .. c:function:: void PyBuffer_FillContiguousStrides(int ndim, Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t itemsize, char order) @@ -492,7 +492,7 @@ On success, set :c:member:`view->obj` to a new reference to *exporter* and return 0. Otherwise, raise :c:data:`PyExc_BufferError`, set - :c:member:`view->obj` to *NULL* and return -1; + :c:member:`view->obj` to *NULL* and return ``-1``; If this function is used as part of a :ref:`getbufferproc `, *exporter* MUST be set to the exporting object and *flags* must be passed diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -120,19 +120,19 @@ guaranteed to succeed. Return a nonzero value if the object is valid and matches the name passed in. - Return 0 otherwise. This function will not fail. + Return ``0`` otherwise. This function will not fail. .. c:function:: int PyCapsule_SetContext(PyObject *capsule, void *context) Set the context pointer inside *capsule* to *context*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor) Set the destructor inside *capsule* to *destructor*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetName(PyObject *capsule, const char *name) @@ -140,11 +140,11 @@ outlive the capsule. If the previous *name* stored in the capsule was not *NULL*, no attempt is made to free it. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetPointer(PyObject *capsule, void *pointer) Set the void pointer inside *capsule* to *pointer*. The pointer may not be *NULL*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -185,10 +185,10 @@ Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` file). The magic number should be present in the first four bytes of the bytecode - file, in little-endian byte order. Returns -1 on error. + file, in little-endian byte order. Returns ``-1`` on error. .. versionchanged:: 3.3 - Return value of -1 upon failure. + Return value of ``-1`` upon failure. .. c:function:: const char * PyImport_GetMagicTag() 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 @@ -44,8 +44,8 @@ .. c:function:: void Py_InitializeEx(int initsigs) - This function works like :c:func:`Py_Initialize` if *initsigs* is 1. If - *initsigs* is 0, it skips initialization registration of signal handlers, which + This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If + *initsigs* is ``0``, it skips initialization registration of signal handlers, which might be useful when Python is embedded. @@ -123,7 +123,7 @@ If :c:func:`Py_FinalizeEx` is called, this function will need to be called again in order to affect subsequent calls to :c:func:`Py_Initialize`. - Returns 0 if successful, a nonzero value on error (e.g. calling after the + Returns ``0`` if successful, a nonzero value on error (e.g. calling after the interpreter has already been initialized). .. versionadded:: 3.4 @@ -358,7 +358,7 @@ - If the name of an existing script is passed in ``argv[0]``, the absolute path of the directory where the script is located is prepended to :data:`sys.path`. - - Otherwise (that is, if *argc* is 0 or ``argv[0]`` doesn't point + - Otherwise (that is, if *argc* is ``0`` or ``argv[0]`` doesn't point to an existing file name), an empty string is prepended to :data:`sys.path`, which is the same as prepending the current working directory (``"."``). @@ -368,7 +368,7 @@ .. note:: It is recommended that applications embedding the Python interpreter - for purposes other than executing a single script pass 0 as *updatepath*, + for purposes other than executing a single script pass ``0`` as *updatepath*, and update :data:`sys.path` themselves if desired. See `CVE-2008-5983 `_. @@ -380,14 +380,14 @@ .. versionadded:: 3.1.3 - .. XXX impl. doesn't seem consistent in allowing 0/NULL for the params; + .. XXX impl. doesn't seem consistent in allowing ``0``/``NULL`` for the params; check w/ Guido. .. c:function:: void PySys_SetArgv(int argc, wchar_t **argv) This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set - to 1 unless the :program:`python` interpreter was started with the + to ``1`` unless the :program:`python` interpreter was started with the :option:`-I`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a @@ -727,10 +727,10 @@ .. c:function:: int PyGILState_Check() - Return 1 if the current thread is holding the GIL and 0 otherwise. + Return ``1`` if the current thread is holding the GIL and ``0`` otherwise. This function can be called from any thread at any time. Only if it has had its Python thread state initialized and currently is - holding the GIL will it return 1. + holding the GIL will it return ``1``. This is mainly a helper/diagnostic function. It can be useful for example in callback contexts or memory allocation functions when knowing that the GIL is locked can allow the caller to perform sensitive @@ -1000,8 +1000,8 @@ .. index:: single: Py_AddPendingCall() Schedule a function to be called from the main interpreter thread. On - success, 0 is returned and *func* is queued for being called in the - main thread. On failure, -1 is returned without setting any exception. + success, ``0`` is returned and *func* is queued for being called in the + main thread. On failure, ``-1`` is returned without setting any exception. When successfully queued, *func* will be *eventually* called from the main interpreter thread with the argument *arg*. It will be called @@ -1012,7 +1012,7 @@ * with the main thread holding the :term:`global interpreter lock` (*func* can therefore use the full C API). - *func* must return 0 on success, or -1 on failure with an exception + *func* must return ``0`` on success, or ``-1`` on failure with an exception set. *func* won't be interrupted to perform another asynchronous notification recursively, but it can still be interrupted to switch threads if the global interpreter lock is released. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -232,7 +232,7 @@ method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:type:`unsigned long`, - return the reduction of that value modulo :const:`ULONG_MAX + 1`. + return the reduction of that value modulo ``ULONG_MAX + 1``. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) @@ -242,7 +242,7 @@ method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:type:`unsigned long long`, - return the reduction of that value modulo :const:`PY_ULLONG_MAX + 1`. + return the reduction of that value modulo ``PY_ULLONG_MAX + 1``. .. c:function:: double PyLong_AsDouble(PyObject *pylong) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -266,7 +266,7 @@ .. c:function:: Py_ssize_t PyNumber_AsSsize_t(PyObject *o, PyObject *exc) Returns *o* converted to a Py_ssize_t value if *o* can be interpreted as an - integer. If the call fails, an exception is raised and -1 is returned. + integer. If the call fails, an exception is raised and ``-1`` is returned. If *o* can be converted to a Python int but the attempt to convert to a Py_ssize_t value would raise an :exc:`OverflowError`, then the diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -114,7 +114,7 @@ .. c:function:: int PySet_Contains(PyObject *anyset, PyObject *key) - Return 1 if found, 0 if not found, and -1 if an error is encountered. Unlike + Return ``1`` if found, ``0`` if not found, and ``-1`` if an error is encountered. Unlike the Python :meth:`__contains__` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise a :exc:`TypeError` if the *key* is unhashable. Raise :exc:`PyExc_SystemError` if *anyset* is not a @@ -125,8 +125,8 @@ Add *key* to a :class:`set` instance. Also works with :class:`frozenset` instances (like :c:func:`PyTuple_SetItem` it can be used to fill-in the values - of brand new frozensets before they are exposed to other code). Return 0 on - success or -1 on failure. Raise a :exc:`TypeError` if the *key* is + of brand new frozensets before they are exposed to other code). Return ``0`` on + success or ``-1`` on failure. Raise a :exc:`TypeError` if the *key* is unhashable. Raise a :exc:`MemoryError` if there is no room to grow. Raise a :exc:`SystemError` if *set* is not an instance of :class:`set` or its subtype. @@ -138,7 +138,7 @@ .. c:function:: int PySet_Discard(PyObject *set, PyObject *key) - Return 1 if found and removed, 0 if not found (no action taken), and -1 if an + Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard` method, this function does not automatically convert unhashable sets into diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -32,9 +32,9 @@ assuming a sequence of length *length*. Treats indices greater than *length* as errors. - Returns 0 on success and -1 on error with no exception set (unless one of + Returns ``0`` on success and ``-1`` on error with no exception set (unless one of the indices was not :const:`None` and failed to be converted to an integer, - in which case -1 is returned with an exception set). + in which case ``-1`` is returned with an exception set). You probably do not want to use this function. @@ -51,7 +51,7 @@ of bounds indices are clipped in a manner consistent with the handling of normal slices. - Returns 0 on success and -1 on error with exception set. + Returns ``0`` on success and ``-1`` on error with exception set. .. versionchanged:: 3.2 The parameter type for the *slice* parameter was ``PySliceObject*`` diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -291,7 +291,7 @@ handles use of the :keyword:`del` statement on that attribute more correctly than :c:macro:`T_OBJECT`. - :attr:`flags` can be 0 for write and read access or :c:macro:`READONLY` for + :attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for read-only access. Using :c:macro:`T_STRING` for :attr:`type` implies :c:macro:`READONLY`. Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX` members can be deleted. (They are set to *NULL*). diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1278,7 +1278,7 @@ steps: (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to *NULL* and return -1. + set :c:data:`view->obj` to *NULL* and return ``-1``. (2) Fill in the requested fields. @@ -1286,7 +1286,7 @@ (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. - (5) Return 0. + (5) Return ``0``. If *exporter* is part of a chain or tree of buffer providers, two main schemes can be used: @@ -1329,7 +1329,7 @@ (1) Decrement an internal counter for the number of exports. - (2) If the counter is 0, free all memory associated with *view*. + (2) If the counter is ``0``, free all memory associated with *view*. The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep track of buffer-specific resources. This field is guaranteed to remain 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 @@ -102,7 +102,7 @@ .. XXX expand on when it is not required - Returns 0 on success and -1 with an exception set on failure, which in + Returns ``0`` on success and ``-1`` with an exception set on failure, which in particular happens if memory allocation fails. .. versionadded:: 3.3 @@ -255,57 +255,57 @@ .. c:function:: int Py_UNICODE_ISSPACE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a whitespace character. + Return ``1`` or ``0`` depending on whether *ch* is a whitespace character. .. c:function:: int Py_UNICODE_ISLOWER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a lowercase character. + Return ``1`` or ``0`` depending on whether *ch* is a lowercase character. .. c:function:: int Py_UNICODE_ISUPPER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an uppercase character. + Return ``1`` or ``0`` depending on whether *ch* is an uppercase character. .. c:function:: int Py_UNICODE_ISTITLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a titlecase character. + Return ``1`` or ``0`` depending on whether *ch* is a titlecase character. .. c:function:: int Py_UNICODE_ISLINEBREAK(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a linebreak character. + Return ``1`` or ``0`` depending on whether *ch* is a linebreak character. .. c:function:: int Py_UNICODE_ISDECIMAL(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a decimal character. + Return ``1`` or ``0`` depending on whether *ch* is a decimal character. .. c:function:: int Py_UNICODE_ISDIGIT(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a digit character. + Return ``1`` or ``0`` depending on whether *ch* is a digit character. .. c:function:: int Py_UNICODE_ISNUMERIC(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a numeric character. + Return ``1`` or ``0`` depending on whether *ch* is a numeric character. .. c:function:: int Py_UNICODE_ISALPHA(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphabetic character. + Return ``1`` or ``0`` depending on whether *ch* is an alphabetic character. .. c:function:: int Py_UNICODE_ISALNUM(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphanumeric character. + Return ``1`` or ``0`` depending on whether *ch* is an alphanumeric character. .. c:function:: int Py_UNICODE_ISPRINTABLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a printable character. + Return ``1`` or ``0`` depending on whether *ch* is a printable character. Nonprintable characters are those characters defined in the Unicode character database as "Other" or "Separator", excepting the ASCII space (0x20) which is considered printable. (Note that printable characters in this context are @@ -908,7 +908,7 @@ .. 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, + Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return *NULL* on failure. @@ -918,7 +918,7 @@ Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing null termination character). Return the number of :c:type:`wchar_t` characters - copied or -1 in case of an error. Note that the resulting :c:type:`wchar_t*` + copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller to make sure that the :c:type:`wchar_t*` string is null-terminated in case this is required by the application. Also, note that the :c:type:`wchar_t*` string @@ -1566,7 +1566,7 @@ .. c:function:: PyObject* PyUnicode_Splitlines(PyObject *s, int keepend) Split a Unicode string at line breaks, returning a list of Unicode strings. - CRLF is considered to be one line break. If *keepend* is 0, the Line break + CRLF is considered to be one line break. If *keepend* is ``0``, the Line break characters are not included in the resulting strings. @@ -1596,16 +1596,16 @@ .. c:function:: Py_ssize_t 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 - (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), - 0 otherwise. Return ``-1`` if an error occurred. + 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 - *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a + *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 occurred and an exception has been set. @@ -1615,8 +1615,8 @@ Py_ssize_t start, Py_ssize_t end, int direction) Return the first position of the character *ch* 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 + 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 occurred and an exception has been set. @@ -1634,19 +1634,19 @@ PyObject *replstr, Py_ssize_t maxcount) Replace at most *maxcount* occurrences of *substr* in *str* with *replstr* and - return the resulting Unicode object. *maxcount* == -1 means replace all + return the resulting Unicode object. *maxcount* == ``-1`` means replace all occurrences. .. c:function:: int PyUnicode_Compare(PyObject *left, PyObject *right) - Compare two strings and return -1, 0, 1 for less than, equal, and greater than, + Compare two strings and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. .. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, const char *string) - Compare a unicode object, *uni*, with *string* and return -1, 0, 1 for less + Compare a unicode object, *uni*, with *string* and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. It is best to pass only ASCII-encoded strings, but the function interprets the input string as ISO-8859-1 if it contains non-ASCII characters. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 14:43:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 18:43:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDk2?= =?utf-8?q?=3A_Mark_up_constants_0=2C_1_and_-1_that_denote_return_values_o?= =?utf-8?q?r?= Message-ID: <20161027184316.62100.25163.F8462C08@psf.io> https://hg.python.org/cpython/rev/04065efd7747 changeset: 104749:04065efd7747 branch: 3.5 parent: 104743:bea48e72cae5 user: Serhiy Storchaka date: Thu Oct 27 21:41:19 2016 +0300 summary: Issue #28496: Mark up constants 0, 1 and -1 that denote return values or special input values as literal text. files: Doc/c-api/arg.rst | 2 +- Doc/c-api/buffer.rst | 12 +++--- Doc/c-api/capsule.rst | 10 ++-- Doc/c-api/import.rst | 4 +- Doc/c-api/init.rst | 24 +++++++------- Doc/c-api/long.rst | 4 +- Doc/c-api/number.rst | 2 +- Doc/c-api/set.rst | 8 ++-- Doc/c-api/slice.rst | 6 +- Doc/c-api/structures.rst | 2 +- Doc/c-api/typeobj.rst | 6 +- Doc/c-api/unicode.rst | 48 ++++++++++++++-------------- 12 files changed, 64 insertions(+), 64 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -342,7 +342,7 @@ ``p`` (:class:`bool`) [int] Tests the value passed in for truth (a boolean **p**\ redicate) and converts the result to its equivalent C true/false integer value. - Sets the int to 1 if the expression was true and 0 if it was false. + Sets the int to ``1`` if the expression was true and ``0`` if it was false. This accepts any valid Python value. See :ref:`truth` for more information about how Python tests values for truth. diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -156,7 +156,7 @@ .. c:member:: int ndim The number of dimensions the memory represents as an n-dimensional array. - If it is 0, :c:member:`~Py_buffer.buf` points to a single item representing + If it is ``0``, :c:member:`~Py_buffer.buf` points to a single item representing a scalar. In this case, :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides` and :c:member:`~Py_buffer.suboffsets` MUST be *NULL*. @@ -427,7 +427,7 @@ .. c:function:: int PyObject_CheckBuffer(PyObject *obj) - Return 1 if *obj* supports the buffer interface otherwise 0. When 1 is + Return ``1`` if *obj* supports the buffer interface otherwise ``0``. When ``1`` is returned, it doesn't guarantee that :c:func:`PyObject_GetBuffer` will succeed. @@ -437,7 +437,7 @@ Send a request to *exporter* to fill in *view* as specified by *flags*. If the exporter cannot provide a buffer of the exact type, it MUST raise :c:data:`PyExc_BufferError`, set :c:member:`view->obj` to *NULL* and - return -1. + return ``-1``. On success, fill in *view*, set :c:member:`view->obj` to a new reference to *exporter* and return 0. In the case of chained buffer providers @@ -468,9 +468,9 @@ .. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char order) - Return 1 if the memory defined by the *view* is C-style (*order* is + Return ``1`` if the memory defined by the *view* is C-style (*order* is ``'C'``) or Fortran-style (*order* is ``'F'``) :term:`contiguous` or either one - (*order* is ``'A'``). Return 0 otherwise. + (*order* is ``'A'``). Return ``0`` otherwise. .. c:function:: void PyBuffer_FillContiguousStrides(int ndim, Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t itemsize, char order) @@ -492,7 +492,7 @@ On success, set :c:member:`view->obj` to a new reference to *exporter* and return 0. Otherwise, raise :c:data:`PyExc_BufferError`, set - :c:member:`view->obj` to *NULL* and return -1; + :c:member:`view->obj` to *NULL* and return ``-1``; If this function is used as part of a :ref:`getbufferproc `, *exporter* MUST be set to the exporting object and *flags* must be passed diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -120,19 +120,19 @@ guaranteed to succeed. Return a nonzero value if the object is valid and matches the name passed in. - Return 0 otherwise. This function will not fail. + Return ``0`` otherwise. This function will not fail. .. c:function:: int PyCapsule_SetContext(PyObject *capsule, void *context) Set the context pointer inside *capsule* to *context*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor) Set the destructor inside *capsule* to *destructor*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetName(PyObject *capsule, const char *name) @@ -140,11 +140,11 @@ outlive the capsule. If the previous *name* stored in the capsule was not *NULL*, no attempt is made to free it. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetPointer(PyObject *capsule, void *pointer) Set the void pointer inside *capsule* to *pointer*. The pointer may not be *NULL*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -185,10 +185,10 @@ Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` file). The magic number should be present in the first four bytes of the bytecode - file, in little-endian byte order. Returns -1 on error. + file, in little-endian byte order. Returns ``-1`` on error. .. versionchanged:: 3.3 - Return value of -1 upon failure. + Return value of ``-1`` upon failure. .. c:function:: const char * PyImport_GetMagicTag() 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 @@ -44,8 +44,8 @@ .. c:function:: void Py_InitializeEx(int initsigs) - This function works like :c:func:`Py_Initialize` if *initsigs* is 1. If - *initsigs* is 0, it skips initialization registration of signal handlers, which + This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If + *initsigs* is ``0``, it skips initialization registration of signal handlers, which might be useful when Python is embedded. @@ -114,7 +114,7 @@ If :c:func:`Py_Finalize` is called, this function will need to be called again in order to affect subsequent calls to :c:func:`Py_Initialize`. - Returns 0 if successful, a nonzero value on error (e.g. calling after the + Returns ``0`` if successful, a nonzero value on error (e.g. calling after the interpreter has already been initialized). .. versionadded:: 3.4 @@ -349,7 +349,7 @@ - If the name of an existing script is passed in ``argv[0]``, the absolute path of the directory where the script is located is prepended to :data:`sys.path`. - - Otherwise (that is, if *argc* is 0 or ``argv[0]`` doesn't point + - Otherwise (that is, if *argc* is ``0`` or ``argv[0]`` doesn't point to an existing file name), an empty string is prepended to :data:`sys.path`, which is the same as prepending the current working directory (``"."``). @@ -359,7 +359,7 @@ .. note:: It is recommended that applications embedding the Python interpreter - for purposes other than executing a single script pass 0 as *updatepath*, + for purposes other than executing a single script pass ``0`` as *updatepath*, and update :data:`sys.path` themselves if desired. See `CVE-2008-5983 `_. @@ -371,14 +371,14 @@ .. versionadded:: 3.1.3 - .. XXX impl. doesn't seem consistent in allowing 0/NULL for the params; + .. XXX impl. doesn't seem consistent in allowing ``0``/``NULL`` for the params; check w/ Guido. .. c:function:: void PySys_SetArgv(int argc, wchar_t **argv) This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set - to 1 unless the :program:`python` interpreter was started with the + to ``1`` unless the :program:`python` interpreter was started with the :option:`-I`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a @@ -718,10 +718,10 @@ .. c:function:: int PyGILState_Check() - Return 1 if the current thread is holding the GIL and 0 otherwise. + Return ``1`` if the current thread is holding the GIL and ``0`` otherwise. This function can be called from any thread at any time. Only if it has had its Python thread state initialized and currently is - holding the GIL will it return 1. + holding the GIL will it return ``1``. This is mainly a helper/diagnostic function. It can be useful for example in callback contexts or memory allocation functions when knowing that the GIL is locked can allow the caller to perform sensitive @@ -991,8 +991,8 @@ .. index:: single: Py_AddPendingCall() Schedule a function to be called from the main interpreter thread. On - success, 0 is returned and *func* is queued for being called in the - main thread. On failure, -1 is returned without setting any exception. + success, ``0`` is returned and *func* is queued for being called in the + main thread. On failure, ``-1`` is returned without setting any exception. When successfully queued, *func* will be *eventually* called from the main interpreter thread with the argument *arg*. It will be called @@ -1003,7 +1003,7 @@ * with the main thread holding the :term:`global interpreter lock` (*func* can therefore use the full C API). - *func* must return 0 on success, or -1 on failure with an exception + *func* must return ``0`` on success, or ``-1`` on failure with an exception set. *func* won't be interrupted to perform another asynchronous notification recursively, but it can still be interrupted to switch threads if the global interpreter lock is released. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -232,7 +232,7 @@ method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:type:`unsigned long`, - return the reduction of that value modulo :const:`ULONG_MAX + 1`. + return the reduction of that value modulo ``ULONG_MAX + 1``. .. c:function:: unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(PyObject *obj) @@ -242,7 +242,7 @@ method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:type:`unsigned long long`, - return the reduction of that value modulo :const:`PY_ULLONG_MAX + 1`. + return the reduction of that value modulo ``PY_ULLONG_MAX + 1``. .. c:function:: double PyLong_AsDouble(PyObject *pylong) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -266,7 +266,7 @@ .. c:function:: Py_ssize_t PyNumber_AsSsize_t(PyObject *o, PyObject *exc) Returns *o* converted to a Py_ssize_t value if *o* can be interpreted as an - integer. If the call fails, an exception is raised and -1 is returned. + integer. If the call fails, an exception is raised and ``-1`` is returned. If *o* can be converted to a Python int but the attempt to convert to a Py_ssize_t value would raise an :exc:`OverflowError`, then the diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -114,7 +114,7 @@ .. c:function:: int PySet_Contains(PyObject *anyset, PyObject *key) - Return 1 if found, 0 if not found, and -1 if an error is encountered. Unlike + Return ``1`` if found, ``0`` if not found, and ``-1`` if an error is encountered. Unlike the Python :meth:`__contains__` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise a :exc:`TypeError` if the *key* is unhashable. Raise :exc:`PyExc_SystemError` if *anyset* is not a @@ -125,8 +125,8 @@ Add *key* to a :class:`set` instance. Also works with :class:`frozenset` instances (like :c:func:`PyTuple_SetItem` it can be used to fill-in the values - of brand new frozensets before they are exposed to other code). Return 0 on - success or -1 on failure. Raise a :exc:`TypeError` if the *key* is + of brand new frozensets before they are exposed to other code). Return ``0`` on + success or ``-1`` on failure. Raise a :exc:`TypeError` if the *key* is unhashable. Raise a :exc:`MemoryError` if there is no room to grow. Raise a :exc:`SystemError` if *set* is not an instance of :class:`set` or its subtype. @@ -138,7 +138,7 @@ .. c:function:: int PySet_Discard(PyObject *set, PyObject *key) - Return 1 if found and removed, 0 if not found (no action taken), and -1 if an + Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard` method, this function does not automatically convert unhashable sets into diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -32,9 +32,9 @@ assuming a sequence of length *length*. Treats indices greater than *length* as errors. - Returns 0 on success and -1 on error with no exception set (unless one of + Returns ``0`` on success and ``-1`` on error with no exception set (unless one of the indices was not :const:`None` and failed to be converted to an integer, - in which case -1 is returned with an exception set). + in which case ``-1`` is returned with an exception set). You probably do not want to use this function. @@ -51,7 +51,7 @@ of bounds indices are clipped in a manner consistent with the handling of normal slices. - Returns 0 on success and -1 on error with exception set. + Returns ``0`` on success and ``-1`` on error with exception set. .. versionchanged:: 3.2 The parameter type for the *slice* parameter was ``PySliceObject*`` diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -290,7 +290,7 @@ handles use of the :keyword:`del` statement on that attribute more correctly than :c:macro:`T_OBJECT`. - :attr:`flags` can be 0 for write and read access or :c:macro:`READONLY` for + :attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for read-only access. Using :c:macro:`T_STRING` for :attr:`type` implies :c:macro:`READONLY`. Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX` members can be deleted. (They are set to *NULL*). diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1278,7 +1278,7 @@ steps: (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to *NULL* and return -1. + set :c:data:`view->obj` to *NULL* and return ``-1``. (2) Fill in the requested fields. @@ -1286,7 +1286,7 @@ (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. - (5) Return 0. + (5) Return ``0``. If *exporter* is part of a chain or tree of buffer providers, two main schemes can be used: @@ -1329,7 +1329,7 @@ (1) Decrement an internal counter for the number of exports. - (2) If the counter is 0, free all memory associated with *view*. + (2) If the counter is ``0``, free all memory associated with *view*. The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep track of buffer-specific resources. This field is guaranteed to remain 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 @@ -102,7 +102,7 @@ .. XXX expand on when it is not required - Returns 0 on success and -1 with an exception set on failure, which in + Returns ``0`` on success and ``-1`` with an exception set on failure, which in particular happens if memory allocation fails. .. versionadded:: 3.3 @@ -255,57 +255,57 @@ .. c:function:: int Py_UNICODE_ISSPACE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a whitespace character. + Return ``1`` or ``0`` depending on whether *ch* is a whitespace character. .. c:function:: int Py_UNICODE_ISLOWER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a lowercase character. + Return ``1`` or ``0`` depending on whether *ch* is a lowercase character. .. c:function:: int Py_UNICODE_ISUPPER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an uppercase character. + Return ``1`` or ``0`` depending on whether *ch* is an uppercase character. .. c:function:: int Py_UNICODE_ISTITLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a titlecase character. + Return ``1`` or ``0`` depending on whether *ch* is a titlecase character. .. c:function:: int Py_UNICODE_ISLINEBREAK(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a linebreak character. + Return ``1`` or ``0`` depending on whether *ch* is a linebreak character. .. c:function:: int Py_UNICODE_ISDECIMAL(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a decimal character. + Return ``1`` or ``0`` depending on whether *ch* is a decimal character. .. c:function:: int Py_UNICODE_ISDIGIT(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a digit character. + Return ``1`` or ``0`` depending on whether *ch* is a digit character. .. c:function:: int Py_UNICODE_ISNUMERIC(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a numeric character. + Return ``1`` or ``0`` depending on whether *ch* is a numeric character. .. c:function:: int Py_UNICODE_ISALPHA(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphabetic character. + Return ``1`` or ``0`` depending on whether *ch* is an alphabetic character. .. c:function:: int Py_UNICODE_ISALNUM(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphanumeric character. + Return ``1`` or ``0`` depending on whether *ch* is an alphanumeric character. .. c:function:: int Py_UNICODE_ISPRINTABLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a printable character. + Return ``1`` or ``0`` depending on whether *ch* is a printable character. Nonprintable characters are those characters defined in the Unicode character database as "Other" or "Separator", excepting the ASCII space (0x20) which is considered printable. (Note that printable characters in this context are @@ -903,7 +903,7 @@ .. 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, + Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return *NULL* on failure. @@ -913,7 +913,7 @@ Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing null termination character). Return the number of :c:type:`wchar_t` characters - copied or -1 in case of an error. Note that the resulting :c:type:`wchar_t*` + copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller to make sure that the :c:type:`wchar_t*` string is null-terminated in case this is required by the application. Also, note that the :c:type:`wchar_t*` string @@ -1561,7 +1561,7 @@ .. c:function:: PyObject* PyUnicode_Splitlines(PyObject *s, int keepend) Split a Unicode string at line breaks, returning a list of Unicode strings. - CRLF is considered to be one line break. If *keepend* is 0, the Line break + CRLF is considered to be one line break. If *keepend* is ``0``, the Line break characters are not included in the resulting strings. @@ -1591,16 +1591,16 @@ .. c:function:: Py_ssize_t 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 - (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), - 0 otherwise. Return ``-1`` if an error occurred. + 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 - *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a + *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 occurred and an exception has been set. @@ -1610,8 +1610,8 @@ Py_ssize_t start, Py_ssize_t end, int direction) Return the first position of the character *ch* 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 + 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 occurred and an exception has been set. @@ -1629,19 +1629,19 @@ PyObject *replstr, Py_ssize_t maxcount) Replace at most *maxcount* occurrences of *substr* in *str* with *replstr* and - return the resulting Unicode object. *maxcount* == -1 means replace all + return the resulting Unicode object. *maxcount* == ``-1`` means replace all occurrences. .. c:function:: int PyUnicode_Compare(PyObject *left, PyObject *right) - Compare two strings and return -1, 0, 1 for less than, equal, and greater than, + Compare two strings and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. .. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, const char *string) - Compare a unicode object, *uni*, with *string* and return -1, 0, 1 for less + Compare a unicode object, *uni*, with *string* and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. It is best to pass only ASCII-encoded strings, but the function interprets the input string as ISO-8859-1 if it contains non-ASCII characters. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 14:43:17 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 18:43:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328496=3A_Mark_up_constants_0=2C_1_and_-1_that_d?= =?utf-8?q?enote_return_values_or?= Message-ID: <20161027184317.62357.2782.0C74B84D@psf.io> https://hg.python.org/cpython/rev/e19f2428b15a changeset: 104751:e19f2428b15a parent: 104747:50c28727d91c parent: 104750:de00be368f0b user: Serhiy Storchaka date: Thu Oct 27 21:42:49 2016 +0300 summary: Issue #28496: Mark up constants 0, 1 and -1 that denote return values or special input values as literal text. files: Doc/c-api/arg.rst | 2 +- Doc/c-api/buffer.rst | 12 +++--- Doc/c-api/capsule.rst | 10 ++-- Doc/c-api/import.rst | 4 +- Doc/c-api/init.rst | 24 +++++++------- Doc/c-api/long.rst | 4 +- Doc/c-api/number.rst | 2 +- Doc/c-api/set.rst | 8 ++-- Doc/c-api/slice.rst | 6 +- Doc/c-api/structures.rst | 2 +- Doc/c-api/typeobj.rst | 6 +- Doc/c-api/unicode.rst | 48 ++++++++++++++-------------- 12 files changed, 64 insertions(+), 64 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -338,7 +338,7 @@ ``p`` (:class:`bool`) [int] Tests the value passed in for truth (a boolean **p**\ redicate) and converts the result to its equivalent C true/false integer value. - Sets the int to 1 if the expression was true and 0 if it was false. + Sets the int to ``1`` if the expression was true and ``0`` if it was false. This accepts any valid Python value. See :ref:`truth` for more information about how Python tests values for truth. diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -156,7 +156,7 @@ .. c:member:: int ndim The number of dimensions the memory represents as an n-dimensional array. - If it is 0, :c:member:`~Py_buffer.buf` points to a single item representing + If it is ``0``, :c:member:`~Py_buffer.buf` points to a single item representing a scalar. In this case, :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides` and :c:member:`~Py_buffer.suboffsets` MUST be *NULL*. @@ -427,7 +427,7 @@ .. c:function:: int PyObject_CheckBuffer(PyObject *obj) - Return 1 if *obj* supports the buffer interface otherwise 0. When 1 is + Return ``1`` if *obj* supports the buffer interface otherwise ``0``. When ``1`` is returned, it doesn't guarantee that :c:func:`PyObject_GetBuffer` will succeed. @@ -437,7 +437,7 @@ Send a request to *exporter* to fill in *view* as specified by *flags*. If the exporter cannot provide a buffer of the exact type, it MUST raise :c:data:`PyExc_BufferError`, set :c:member:`view->obj` to *NULL* and - return -1. + return ``-1``. On success, fill in *view*, set :c:member:`view->obj` to a new reference to *exporter* and return 0. In the case of chained buffer providers @@ -468,9 +468,9 @@ .. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char order) - Return 1 if the memory defined by the *view* is C-style (*order* is + Return ``1`` if the memory defined by the *view* is C-style (*order* is ``'C'``) or Fortran-style (*order* is ``'F'``) :term:`contiguous` or either one - (*order* is ``'A'``). Return 0 otherwise. + (*order* is ``'A'``). Return ``0`` otherwise. .. c:function:: void PyBuffer_FillContiguousStrides(int ndim, Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t itemsize, char order) @@ -492,7 +492,7 @@ On success, set :c:member:`view->obj` to a new reference to *exporter* and return 0. Otherwise, raise :c:data:`PyExc_BufferError`, set - :c:member:`view->obj` to *NULL* and return -1; + :c:member:`view->obj` to *NULL* and return ``-1``; If this function is used as part of a :ref:`getbufferproc `, *exporter* MUST be set to the exporting object and *flags* must be passed diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -120,19 +120,19 @@ guaranteed to succeed. Return a nonzero value if the object is valid and matches the name passed in. - Return 0 otherwise. This function will not fail. + Return ``0`` otherwise. This function will not fail. .. c:function:: int PyCapsule_SetContext(PyObject *capsule, void *context) Set the context pointer inside *capsule* to *context*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor) Set the destructor inside *capsule* to *destructor*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetName(PyObject *capsule, const char *name) @@ -140,11 +140,11 @@ outlive the capsule. If the previous *name* stored in the capsule was not *NULL*, no attempt is made to free it. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. .. c:function:: int PyCapsule_SetPointer(PyObject *capsule, void *pointer) Set the void pointer inside *capsule* to *pointer*. The pointer may not be *NULL*. - Return 0 on success. Return nonzero and set an exception on failure. + Return ``0`` on success. Return nonzero and set an exception on failure. diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -185,10 +185,10 @@ Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` file). The magic number should be present in the first four bytes of the bytecode - file, in little-endian byte order. Returns -1 on error. + file, in little-endian byte order. Returns ``-1`` on error. .. versionchanged:: 3.3 - Return value of -1 upon failure. + Return value of ``-1`` upon failure. .. c:function:: const char * PyImport_GetMagicTag() 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 @@ -44,8 +44,8 @@ .. c:function:: void Py_InitializeEx(int initsigs) - This function works like :c:func:`Py_Initialize` if *initsigs* is 1. If - *initsigs* is 0, it skips initialization registration of signal handlers, which + This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If + *initsigs* is ``0``, it skips initialization registration of signal handlers, which might be useful when Python is embedded. @@ -123,7 +123,7 @@ If :c:func:`Py_FinalizeEx` is called, this function will need to be called again in order to affect subsequent calls to :c:func:`Py_Initialize`. - Returns 0 if successful, a nonzero value on error (e.g. calling after the + Returns ``0`` if successful, a nonzero value on error (e.g. calling after the interpreter has already been initialized). .. versionadded:: 3.4 @@ -358,7 +358,7 @@ - If the name of an existing script is passed in ``argv[0]``, the absolute path of the directory where the script is located is prepended to :data:`sys.path`. - - Otherwise (that is, if *argc* is 0 or ``argv[0]`` doesn't point + - Otherwise (that is, if *argc* is ``0`` or ``argv[0]`` doesn't point to an existing file name), an empty string is prepended to :data:`sys.path`, which is the same as prepending the current working directory (``"."``). @@ -368,7 +368,7 @@ .. note:: It is recommended that applications embedding the Python interpreter - for purposes other than executing a single script pass 0 as *updatepath*, + for purposes other than executing a single script pass ``0`` as *updatepath*, and update :data:`sys.path` themselves if desired. See `CVE-2008-5983 `_. @@ -380,14 +380,14 @@ .. versionadded:: 3.1.3 - .. XXX impl. doesn't seem consistent in allowing 0/NULL for the params; + .. XXX impl. doesn't seem consistent in allowing ``0``/``NULL`` for the params; check w/ Guido. .. c:function:: void PySys_SetArgv(int argc, wchar_t **argv) This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set - to 1 unless the :program:`python` interpreter was started with the + to ``1`` unless the :program:`python` interpreter was started with the :option:`-I`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a @@ -727,10 +727,10 @@ .. c:function:: int PyGILState_Check() - Return 1 if the current thread is holding the GIL and 0 otherwise. + Return ``1`` if the current thread is holding the GIL and ``0`` otherwise. This function can be called from any thread at any time. Only if it has had its Python thread state initialized and currently is - holding the GIL will it return 1. + holding the GIL will it return ``1``. This is mainly a helper/diagnostic function. It can be useful for example in callback contexts or memory allocation functions when knowing that the GIL is locked can allow the caller to perform sensitive @@ -1000,8 +1000,8 @@ .. index:: single: Py_AddPendingCall() Schedule a function to be called from the main interpreter thread. On - success, 0 is returned and *func* is queued for being called in the - main thread. On failure, -1 is returned without setting any exception. + success, ``0`` is returned and *func* is queued for being called in the + main thread. On failure, ``-1`` is returned without setting any exception. When successfully queued, *func* will be *eventually* called from the main interpreter thread with the argument *arg*. It will be called @@ -1012,7 +1012,7 @@ * with the main thread holding the :term:`global interpreter lock` (*func* can therefore use the full C API). - *func* must return 0 on success, or -1 on failure with an exception + *func* must return ``0`` on success, or ``-1`` on failure with an exception set. *func* won't be interrupted to perform another asynchronous notification recursively, but it can still be interrupted to switch threads if the global interpreter lock is released. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -232,7 +232,7 @@ method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:type:`unsigned long`, - return the reduction of that value modulo :const:`ULONG_MAX + 1`. + return the reduction of that value modulo ``ULONG_MAX + 1``. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) @@ -242,7 +242,7 @@ method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:type:`unsigned long long`, - return the reduction of that value modulo :const:`PY_ULLONG_MAX + 1`. + return the reduction of that value modulo ``PY_ULLONG_MAX + 1``. .. c:function:: double PyLong_AsDouble(PyObject *pylong) diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -266,7 +266,7 @@ .. c:function:: Py_ssize_t PyNumber_AsSsize_t(PyObject *o, PyObject *exc) Returns *o* converted to a Py_ssize_t value if *o* can be interpreted as an - integer. If the call fails, an exception is raised and -1 is returned. + integer. If the call fails, an exception is raised and ``-1`` is returned. If *o* can be converted to a Python int but the attempt to convert to a Py_ssize_t value would raise an :exc:`OverflowError`, then the diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -114,7 +114,7 @@ .. c:function:: int PySet_Contains(PyObject *anyset, PyObject *key) - Return 1 if found, 0 if not found, and -1 if an error is encountered. Unlike + Return ``1`` if found, ``0`` if not found, and ``-1`` if an error is encountered. Unlike the Python :meth:`__contains__` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise a :exc:`TypeError` if the *key* is unhashable. Raise :exc:`PyExc_SystemError` if *anyset* is not a @@ -125,8 +125,8 @@ Add *key* to a :class:`set` instance. Also works with :class:`frozenset` instances (like :c:func:`PyTuple_SetItem` it can be used to fill-in the values - of brand new frozensets before they are exposed to other code). Return 0 on - success or -1 on failure. Raise a :exc:`TypeError` if the *key* is + of brand new frozensets before they are exposed to other code). Return ``0`` on + success or ``-1`` on failure. Raise a :exc:`TypeError` if the *key* is unhashable. Raise a :exc:`MemoryError` if there is no room to grow. Raise a :exc:`SystemError` if *set* is not an instance of :class:`set` or its subtype. @@ -138,7 +138,7 @@ .. c:function:: int PySet_Discard(PyObject *set, PyObject *key) - Return 1 if found and removed, 0 if not found (no action taken), and -1 if an + Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard` method, this function does not automatically convert unhashable sets into diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -32,9 +32,9 @@ assuming a sequence of length *length*. Treats indices greater than *length* as errors. - Returns 0 on success and -1 on error with no exception set (unless one of + Returns ``0`` on success and ``-1`` on error with no exception set (unless one of the indices was not :const:`None` and failed to be converted to an integer, - in which case -1 is returned with an exception set). + in which case ``-1`` is returned with an exception set). You probably do not want to use this function. @@ -51,7 +51,7 @@ of bounds indices are clipped in a manner consistent with the handling of normal slices. - Returns 0 on success and -1 on error with exception set. + Returns ``0`` on success and ``-1`` on error with exception set. .. versionchanged:: 3.2 The parameter type for the *slice* parameter was ``PySliceObject*`` diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -291,7 +291,7 @@ handles use of the :keyword:`del` statement on that attribute more correctly than :c:macro:`T_OBJECT`. - :attr:`flags` can be 0 for write and read access or :c:macro:`READONLY` for + :attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for read-only access. Using :c:macro:`T_STRING` for :attr:`type` implies :c:macro:`READONLY`. Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX` members can be deleted. (They are set to *NULL*). diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1278,7 +1278,7 @@ steps: (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to *NULL* and return -1. + set :c:data:`view->obj` to *NULL* and return ``-1``. (2) Fill in the requested fields. @@ -1286,7 +1286,7 @@ (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. - (5) Return 0. + (5) Return ``0``. If *exporter* is part of a chain or tree of buffer providers, two main schemes can be used: @@ -1329,7 +1329,7 @@ (1) Decrement an internal counter for the number of exports. - (2) If the counter is 0, free all memory associated with *view*. + (2) If the counter is ``0``, free all memory associated with *view*. The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep track of buffer-specific resources. This field is guaranteed to remain 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 @@ -102,7 +102,7 @@ .. XXX expand on when it is not required - Returns 0 on success and -1 with an exception set on failure, which in + Returns ``0`` on success and ``-1`` with an exception set on failure, which in particular happens if memory allocation fails. .. versionadded:: 3.3 @@ -255,57 +255,57 @@ .. c:function:: int Py_UNICODE_ISSPACE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a whitespace character. + Return ``1`` or ``0`` depending on whether *ch* is a whitespace character. .. c:function:: int Py_UNICODE_ISLOWER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a lowercase character. + Return ``1`` or ``0`` depending on whether *ch* is a lowercase character. .. c:function:: int Py_UNICODE_ISUPPER(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an uppercase character. + Return ``1`` or ``0`` depending on whether *ch* is an uppercase character. .. c:function:: int Py_UNICODE_ISTITLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a titlecase character. + Return ``1`` or ``0`` depending on whether *ch* is a titlecase character. .. c:function:: int Py_UNICODE_ISLINEBREAK(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a linebreak character. + Return ``1`` or ``0`` depending on whether *ch* is a linebreak character. .. c:function:: int Py_UNICODE_ISDECIMAL(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a decimal character. + Return ``1`` or ``0`` depending on whether *ch* is a decimal character. .. c:function:: int Py_UNICODE_ISDIGIT(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a digit character. + Return ``1`` or ``0`` depending on whether *ch* is a digit character. .. c:function:: int Py_UNICODE_ISNUMERIC(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a numeric character. + Return ``1`` or ``0`` depending on whether *ch* is a numeric character. .. c:function:: int Py_UNICODE_ISALPHA(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphabetic character. + Return ``1`` or ``0`` depending on whether *ch* is an alphabetic character. .. c:function:: int Py_UNICODE_ISALNUM(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is an alphanumeric character. + Return ``1`` or ``0`` depending on whether *ch* is an alphanumeric character. .. c:function:: int Py_UNICODE_ISPRINTABLE(Py_UNICODE ch) - Return 1 or 0 depending on whether *ch* is a printable character. + Return ``1`` or ``0`` depending on whether *ch* is a printable character. Nonprintable characters are those characters defined in the Unicode character database as "Other" or "Separator", excepting the ASCII space (0x20) which is considered printable. (Note that printable characters in this context are @@ -908,7 +908,7 @@ .. 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, + Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return *NULL* on failure. @@ -918,7 +918,7 @@ Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing null termination character). Return the number of :c:type:`wchar_t` characters - copied or -1 in case of an error. Note that the resulting :c:type:`wchar_t*` + copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller to make sure that the :c:type:`wchar_t*` string is null-terminated in case this is required by the application. Also, note that the :c:type:`wchar_t*` string @@ -1566,7 +1566,7 @@ .. c:function:: PyObject* PyUnicode_Splitlines(PyObject *s, int keepend) Split a Unicode string at line breaks, returning a list of Unicode strings. - CRLF is considered to be one line break. If *keepend* is 0, the Line break + CRLF is considered to be one line break. If *keepend* is ``0``, the Line break characters are not included in the resulting strings. @@ -1596,16 +1596,16 @@ .. c:function:: Py_ssize_t 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 - (*direction* == -1 means to do a prefix match, *direction* == 1 a suffix match), - 0 otherwise. Return ``-1`` if an error occurred. + 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 - *direction* (*direction* == 1 means to do a forward search, *direction* == -1 a + *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 occurred and an exception has been set. @@ -1615,8 +1615,8 @@ Py_ssize_t start, Py_ssize_t end, int direction) Return the first position of the character *ch* 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 + 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 occurred and an exception has been set. @@ -1634,19 +1634,19 @@ PyObject *replstr, Py_ssize_t maxcount) Replace at most *maxcount* occurrences of *substr* in *str* with *replstr* and - return the resulting Unicode object. *maxcount* == -1 means replace all + return the resulting Unicode object. *maxcount* == ``-1`` means replace all occurrences. .. c:function:: int PyUnicode_Compare(PyObject *left, PyObject *right) - Compare two strings and return -1, 0, 1 for less than, equal, and greater than, + Compare two strings and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. .. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, const char *string) - Compare a unicode object, *uni*, with *string* and return -1, 0, 1 for less + Compare a unicode object, *uni*, with *string* and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. It is best to pass only ASCII-encoded strings, but the function interprets the input string as ISO-8859-1 if it contains non-ASCII characters. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:15:54 2016 From: python-checkins at python.org (steve.dower) Date: Thu, 27 Oct 2016 19:15:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Revert_incorre?= =?utf-8?q?ct_file_merge_from_3=2E5=2E?= Message-ID: <20161027191554.17941.51360.F2ED8D45@psf.io> https://hg.python.org/cpython/rev/fbc4d01ae3f0 changeset: 104754:fbc4d01ae3f0 branch: 3.6 user: Steve Dower date: Thu Oct 27 12:14:48 2016 -0700 summary: Revert incorrect file merge from 3.5. files: Tools/msi/make_zip.proj | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/make_zip.proj b/Tools/msi/make_zip.proj --- a/Tools/msi/make_zip.proj +++ b/Tools/msi/make_zip.proj @@ -16,7 +16,7 @@ $(OutputPath)\en-us\$(TargetName)$(TargetExt) rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)" "$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py" - $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -b "$(OutDir.TrimEnd('\'))" + $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a $(ArchName) set DOC_FILENAME=python$(PythonVersion).chm set VCREDIST_PATH=$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:15:54 2016 From: python-checkins at python.org (steve.dower) Date: Thu, 27 Oct 2016 19:15:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5?= Message-ID: <20161027191554.9757.62510.1766D22D@psf.io> https://hg.python.org/cpython/rev/a231d0d139f9 changeset: 104753:a231d0d139f9 branch: 3.6 parent: 104750:de00be368f0b parent: 104752:e880a93662c8 user: Steve Dower date: Thu Oct 27 12:12:24 2016 -0700 summary: Merge from 3.5 files: Tools/msi/buildrelease.bat | 31 ++++++++++++++++++++----- Tools/msi/make_zip.proj | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -36,6 +36,8 @@ set TARGET=Rebuild set TESTTARGETDIR= set PGO=default +set BUILDNUGET=1 +set BUILDZIP=1 :CheckOpts @@ -56,6 +58,8 @@ if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts if "%1" EQU "--pgo" (set PGO=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts +if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts +if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1 @@ -184,21 +188,31 @@ msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false if errorlevel 1 exit /B -msbuild "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% +if defined BUILDZIP ( + msbuild "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% + if errorlevel 1 exit /B +) + +if defined BUILDNUGET ( + msbuild "%D%..\nuget\make_pkg.proj" /t:Build /p:Configuration=Release /p:Platform=%1 /p:OutputPath="%BUILD%en-us" + if errorlevel 1 exit /B +) if not "%OUTDIR%" EQU "" ( mkdir "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.cab" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.exe" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.msi" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.msu" "%OUTDIR%\%OUTDIR_PLAT%" + mkdir "%OUTDIR%\%OUTDIR_PLAT%\binaries" + mkdir "%OUTDIR%\%OUTDIR_PLAT%\symbols" + robocopy "%BUILD%en-us" "%OUTDIR%\%OUTDIR_PLAT%" /XF "*.wixpdb" + robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\binaries" *.exe *.dll *.pyd /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*" + robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\symbols" *.pdb /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*" ) exit /B 0 :Help -echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--skip-build] -echo [--pgo COMMAND] [--skip-pgo] [--skip-doc] [--download DOWNLOAD URL] [--test TARGETDIR] +echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--pgo COMMAND] +echo [--skip-build] [--skip-doc] [--skip-nuget] [--skip-zip] [--skip-pgo] +echo [--download DOWNLOAD URL] [--test TARGETDIR] echo [-h] echo. echo --out (-o) Specify an additional output directory for installers @@ -209,6 +223,9 @@ echo --skip-doc (-D) Do not build documentation echo --pgo Specify PGO command for x64 installers echo --skip-pgo Build x64 installers using PGO +echo --skip-nuget Do not build Nuget packages +echo --skip-zip Do not build embeddable package +echo --pgo Build x64 installers using PGO echo --download Specify the full download URL for MSIs echo --test Specify the test directory to run the installer tests echo -h Display this help information diff --git a/Tools/msi/make_zip.proj b/Tools/msi/make_zip.proj --- a/Tools/msi/make_zip.proj +++ b/Tools/msi/make_zip.proj @@ -16,7 +16,7 @@ $(OutputPath)\en-us\$(TargetName)$(TargetExt) rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)" "$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py" - $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a "$(ArchName)" + $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -b "$(OutDir.TrimEnd('\'))" set DOC_FILENAME=python$(PythonVersion).chm set VCREDIST_PATH=$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:15:54 2016 From: python-checkins at python.org (steve.dower) Date: Thu, 27 Oct 2016 19:15:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_from_3=2E6?= Message-ID: <20161027191554.9460.19179.8673CF45@psf.io> https://hg.python.org/cpython/rev/05777a9c9b6b changeset: 104755:05777a9c9b6b parent: 104751:e19f2428b15a parent: 104754:fbc4d01ae3f0 user: Steve Dower date: Thu Oct 27 12:15:23 2016 -0700 summary: Merge from 3.6 files: Tools/msi/buildrelease.bat | 31 ++++++++++++++++++++----- Tools/msi/make_zip.proj | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -36,6 +36,8 @@ set TARGET=Rebuild set TESTTARGETDIR= set PGO=default +set BUILDNUGET=1 +set BUILDZIP=1 :CheckOpts @@ -56,6 +58,8 @@ if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts if "%1" EQU "--pgo" (set PGO=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts +if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts +if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1 @@ -182,21 +186,31 @@ msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false if errorlevel 1 exit /B -msbuild "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% +if defined BUILDZIP ( + msbuild "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% + if errorlevel 1 exit /B +) + +if defined BUILDNUGET ( + msbuild "%D%..\nuget\make_pkg.proj" /t:Build /p:Configuration=Release /p:Platform=%1 /p:OutputPath="%BUILD%en-us" + if errorlevel 1 exit /B +) if not "%OUTDIR%" EQU "" ( mkdir "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.cab" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.exe" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.msi" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.msu" "%OUTDIR%\%OUTDIR_PLAT%" + mkdir "%OUTDIR%\%OUTDIR_PLAT%\binaries" + mkdir "%OUTDIR%\%OUTDIR_PLAT%\symbols" + robocopy "%BUILD%en-us" "%OUTDIR%\%OUTDIR_PLAT%" /XF "*.wixpdb" + robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\binaries" *.exe *.dll *.pyd /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*" + robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\symbols" *.pdb /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*" ) exit /B 0 :Help -echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--skip-build] -echo [--pgo COMMAND] [--skip-pgo] [--skip-doc] [--download DOWNLOAD URL] [--test TARGETDIR] +echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--pgo COMMAND] +echo [--skip-build] [--skip-doc] [--skip-nuget] [--skip-zip] [--skip-pgo] +echo [--download DOWNLOAD URL] [--test TARGETDIR] echo [-h] echo. echo --out (-o) Specify an additional output directory for installers @@ -207,6 +221,9 @@ echo --skip-doc (-D) Do not build documentation echo --pgo Specify PGO command for x64 installers echo --skip-pgo Build x64 installers using PGO +echo --skip-nuget Do not build Nuget packages +echo --skip-zip Do not build embeddable package +echo --pgo Build x64 installers using PGO echo --download Specify the full download URL for MSIs echo --test Specify the test directory to run the installer tests echo -h Display this help information diff --git a/Tools/msi/make_zip.proj b/Tools/msi/make_zip.proj --- a/Tools/msi/make_zip.proj +++ b/Tools/msi/make_zip.proj @@ -16,7 +16,7 @@ $(OutputPath)\en-us\$(TargetName)$(TargetExt) rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)" "$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py" - $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a "$(ArchName)" + $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a $(ArchName) set DOC_FILENAME=python$(PythonVersion).chm set VCREDIST_PATH=$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:15:54 2016 From: python-checkins at python.org (steve.dower) Date: Thu, 27 Oct 2016 19:15:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Updates_releas?= =?utf-8?q?e_build_to_collect_symbols_and_binaries=2C_and_create_nuget_pac?= =?utf-8?q?kage=2E?= Message-ID: <20161027191554.18098.78994.3499C6BC@psf.io> https://hg.python.org/cpython/rev/e880a93662c8 changeset: 104752:e880a93662c8 branch: 3.5 parent: 104749:04065efd7747 user: Steve Dower date: Thu Oct 27 12:08:45 2016 -0700 summary: Updates release build to collect symbols and binaries, and create nuget package. files: Tools/msi/buildrelease.bat | 30 +++++++++++++++++++------ Tools/msi/make_zip.proj | 2 +- Tools/nuget/make_pkg.proj | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -36,6 +36,8 @@ set TARGET=Rebuild set TESTTARGETDIR= set PGO= +set BUILDNUGET=1 +set BUILDZIP=1 :CheckOpts @@ -55,6 +57,8 @@ if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts if "%1" EQU "--pgo" (set PGO=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts +if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1 @@ -182,21 +186,31 @@ msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild /p:Platform=%1 %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false if errorlevel 1 exit /B -msbuild "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% +if defined BUILDZIP ( + msbuild "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% + if errorlevel 1 exit /B +) + +if defined BUILDNUGET ( + msbuild "%D%..\nuget\make_pkg.proj" /t:Build /p:Configuration=Release /p:Platform=%1 /p:OutputPath="%BUILD%en-us" + if errorlevel 1 exit /B +) if not "%OUTDIR%" EQU "" ( mkdir "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.cab" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.exe" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.msi" "%OUTDIR%\%OUTDIR_PLAT%" - copy /Y "%BUILD%en-us\*.msu" "%OUTDIR%\%OUTDIR_PLAT%" + mkdir "%OUTDIR%\%OUTDIR_PLAT%\binaries" + mkdir "%OUTDIR%\%OUTDIR_PLAT%\symbols" + robocopy "%BUILD%en-us" "%OUTDIR%\%OUTDIR_PLAT%" /XF "*.wixpdb" + robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\binaries" *.exe *.dll *.pyd /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*" + robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\symbols" *.pdb /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*" ) exit /B 0 :Help -echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--skip-build] -echo [--pgo COMMAND] [--skip-doc] [--download DOWNLOAD URL] [--test TARGETDIR] +echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--pgo COMMAND] +echo [--skip-build] [--skip-doc] [--skip-nuget] [--skip-zip] +echo [--download DOWNLOAD URL] [--test TARGETDIR] echo [-h] echo. echo --out (-o) Specify an additional output directory for installers @@ -205,6 +219,8 @@ echo --build (-b) Incrementally build Python rather than rebuilding echo --skip-build (-B) Do not build Python (just do the installers) echo --skip-doc (-D) Do not build documentation +echo --skip-nuget Do not build Nuget packages +echo --skip-zip Do not build embeddable package echo --pgo Build x64 installers using PGO echo --download Specify the full download URL for MSIs echo --test Specify the test directory to run the installer tests diff --git a/Tools/msi/make_zip.proj b/Tools/msi/make_zip.proj --- a/Tools/msi/make_zip.proj +++ b/Tools/msi/make_zip.proj @@ -16,7 +16,7 @@ $(OutputPath)\en-us\$(TargetName)$(TargetExt) rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)" "$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py" - $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a "$(ArchName)" + $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -b "$(OutDir.TrimEnd('\'))" set DOC_FILENAME=python$(PythonVersion).chm set VCREDIST_PATH=$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT diff --git a/Tools/nuget/make_pkg.proj b/Tools/nuget/make_pkg.proj --- a/Tools/nuget/make_pkg.proj +++ b/Tools/nuget/make_pkg.proj @@ -23,7 +23,7 @@ rmdir /q/s "$(IntermediateOutputPath)" "$(PythonExe)" "$(MSBuildThisFileDirectory)\..\msi\make_zip.py" - $(PythonArguments) -t "$(IntermediateOutputPath)" -a $(ArchName) + $(PythonArguments) -t "$(IntermediateOutputPath)" -b "$(OutDir.TrimEnd('\'))\.." "$(IntermediateOutputPath)\python.exe" -B -c "import sys; sys.path.append(r'$(PySourcePath)\Lib'); import ensurepip; ensurepip._main()" "$(IntermediateOutputPath)\python.exe" -B -m pip install -U $(Packages) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:50:47 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 19:50:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzIyNDkz?= =?utf-8?q?=3A_Updated_an_example_for_fnmatch=2Etranslate=28=29=2E?= Message-ID: <20161027195047.115406.42690.561E4F95@psf.io> https://hg.python.org/cpython/rev/c04a56b3a4f2 changeset: 104756:c04a56b3a4f2 branch: 3.6 parent: 104754:fbc4d01ae3f0 user: Serhiy Storchaka date: Thu Oct 27 22:44:03 2016 +0300 summary: Issue #22493: Updated an example for fnmatch.translate(). files: Doc/library/fnmatch.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -82,7 +82,7 @@ >>> >>> regex = fnmatch.translate('*.txt') >>> regex - '.*\\.txt\\Z(?ms)' + '(?s:.*\\.txt)\\Z' >>> reobj = re.compile(regex) >>> reobj.match('foobar.txt') <_sre.SRE_Match object; span=(0, 10), match='foobar.txt'> -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:50:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 19:50:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322949=3A_Documented_that_fnmatch=2Etranslate=28?= =?utf-8?q?=29_is_for_use_with_re=2Ematch=28=29=2E?= Message-ID: <20161027195047.27271.17105.EC120250@psf.io> https://hg.python.org/cpython/rev/d103ee917342 changeset: 104761:d103ee917342 parent: 104757:ded9a3c3bbb6 parent: 104760:dfda2f33fd08 user: Serhiy Storchaka date: Thu Oct 27 22:50:29 2016 +0300 summary: Issue #22949: Documented that fnmatch.translate() is for use with re.match(). files: Doc/library/fnmatch.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -74,7 +74,8 @@ .. function:: translate(pattern) - Return the shell-style *pattern* converted to a regular expression. + Return the shell-style *pattern* converted to a regular expression for + using with :func:`re.match`. Example: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:50:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 19:50:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIyOTQ5?= =?utf-8?q?=3A_Documented_that_fnmatch=2Etranslate=28=29_is_for_use_with_r?= =?utf-8?b?ZS5tYXRjaCgpLg==?= Message-ID: <20161027195047.25114.20986.8B43E22F@psf.io> https://hg.python.org/cpython/rev/a1aef5f84142 changeset: 104758:a1aef5f84142 branch: 3.5 parent: 104752:e880a93662c8 user: Serhiy Storchaka date: Thu Oct 27 22:47:08 2016 +0300 summary: Issue #22949: Documented that fnmatch.translate() is for use with re.match(). files: Doc/library/fnmatch.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -74,7 +74,8 @@ .. function:: translate(pattern) - Return the shell-style *pattern* converted to a regular expression. + Return the shell-style *pattern* converted to a regular expression for + using with :func:`re.match`. Example: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:50:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 19:50:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyOTQ5?= =?utf-8?q?=3A_Documented_that_fnmatch=2Etranslate=28=29_is_for_use_with_r?= =?utf-8?b?ZS5tYXRjaCgpLg==?= Message-ID: <20161027195047.25135.27739.21DC3368@psf.io> https://hg.python.org/cpython/rev/8a564ab1d208 changeset: 104759:8a564ab1d208 branch: 2.7 parent: 104748:e90fe2209276 user: Serhiy Storchaka date: Thu Oct 27 22:47:08 2016 +0300 summary: Issue #22949: Documented that fnmatch.translate() is for use with re.match(). files: Doc/library/fnmatch.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -77,7 +77,8 @@ .. function:: translate(pattern) - Return the shell-style *pattern* converted to a regular expression. + Return the shell-style *pattern* converted to a regular expression for + using with :func:`re.match`. Example: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:50:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 19:50:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2322949=3A_Documented_that_fnmatch=2Etranslate=28=29_is?= =?utf-8?q?_for_use_with_re=2Ematch=28=29=2E?= Message-ID: <20161027195047.12110.42151.93C2BC34@psf.io> https://hg.python.org/cpython/rev/dfda2f33fd08 changeset: 104760:dfda2f33fd08 branch: 3.6 parent: 104756:c04a56b3a4f2 parent: 104758:a1aef5f84142 user: Serhiy Storchaka date: Thu Oct 27 22:50:15 2016 +0300 summary: Issue #22949: Documented that fnmatch.translate() is for use with re.match(). files: Doc/library/fnmatch.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -74,7 +74,8 @@ .. function:: translate(pattern) - Return the shell-style *pattern* converted to a regular expression. + Return the shell-style *pattern* converted to a regular expression for + using with :func:`re.match`. Example: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 15:50:48 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Oct 2016 19:50:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322493=3A_Updated_an_example_for_fnmatch=2Etrans?= =?utf-8?b?bGF0ZSgpLg==?= Message-ID: <20161027195047.9544.91184.35C90C05@psf.io> https://hg.python.org/cpython/rev/ded9a3c3bbb6 changeset: 104757:ded9a3c3bbb6 parent: 104755:05777a9c9b6b parent: 104756:c04a56b3a4f2 user: Serhiy Storchaka date: Thu Oct 27 22:45:03 2016 +0300 summary: Issue #22493: Updated an example for fnmatch.translate(). files: Doc/library/fnmatch.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -82,7 +82,7 @@ >>> >>> regex = fnmatch.translate('*.txt') >>> regex - '.*\\.txt\\Z(?ms)' + '(?s:.*\\.txt)\\Z' >>> reobj = re.compile(regex) >>> reobj.match('foobar.txt') <_sre.SRE_Match object; span=(0, 10), match='foobar.txt'> -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 17:29:35 2016 From: python-checkins at python.org (steve.dower) Date: Thu, 27 Oct 2016 21:29:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328522=3A_Fixes_mishandled_buffer_reallocation_i?= =?utf-8?q?n_getpathp=2Ec?= Message-ID: <20161027212935.9426.69745.0EEA2016@psf.io> https://hg.python.org/cpython/rev/72e64fc8746b changeset: 104763:72e64fc8746b parent: 104761:d103ee917342 parent: 104762:eea669163131 user: Steve Dower date: Thu Oct 27 14:29:13 2016 -0700 summary: Issue #28522: Fixes mishandled buffer reallocation in getpathp.c files: Lib/test/test_site.py | 52 +++++++++++++++++++++++++++++++ Misc/NEWS | 2 + PC/getpathp.c | 19 ++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -488,6 +488,58 @@ 'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()") + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") + def test_underpth_nosite_file(self): + _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + try: + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + with open(_pth_file, 'w') as f: + print('fake-path-name', file=f) + # Ensure the generated path is very long so that buffer + # resizing in getpathp.c is exercised + for _ in range(200): + print(libpath, file=f) + print('# comment', file=f) + + env = os.environ.copy() + env['PYTHONPATH'] = 'from-env' + rc = subprocess.call([sys.executable, '-c', + 'import sys; sys.exit(sys.flags.no_site and ' + 'len(sys.path) > 200 and ' + '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( + os.path.join(sys.prefix, 'fake-path-name'), + libpath, + os.path.join(sys.prefix, 'from-env'), + )], env=env) + self.assertEqual(rc, 0) + finally: + os.unlink(_pth_file) + + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") + def test_underpth_file(self): + _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + try: + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + with open(_pth_file, 'w') as f: + print('fake-path-name', file=f) + for _ in range(200): + print(libpath, file=f) + print('# comment', file=f) + print('import site', file=f) + + env = os.environ.copy() + env['PYTHONPATH'] = 'from-env' + rc = subprocess.call([sys.executable, '-c', + 'import sys; sys.exit(not sys.flags.no_site and ' + '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( + os.path.join(sys.prefix, 'fake-path-name'), + libpath, + os.path.join(sys.prefix, 'from-env'), + )], env=env) + self.assertEqual(rc, 0) + finally: + os.unlink(_pth_file) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -321,6 +321,8 @@ Windows ------- +- Issue #28522: Fixes mishandled buffer reallocation in getpathp.c + - Issue #28402: Adds signed catalog files for stdlib on Windows. - Issue #28333: Enables Unicode for ps1/ps2 and input() prompts. (Patch by diff --git a/PC/getpathp.c b/PC/getpathp.c --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -581,7 +581,8 @@ wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1); wline[wn] = '\0'; - while (wn + prefixlen + 4 > bufsiz) { + size_t usedsiz = wcslen(buf); + while (usedsiz + wn + prefixlen + 4 > bufsiz) { bufsiz += MAXPATHLEN; buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t)); if (!buf) { @@ -590,11 +591,21 @@ } } - if (buf[0]) + if (usedsiz) { wcscat_s(buf, bufsiz, L";"); + usedsiz += 1; + } - wchar_t *b = &buf[wcslen(buf)]; - wcscat_s(buf, bufsiz, prefix); + errno_t result; + _Py_BEGIN_SUPPRESS_IPH + result = wcscat_s(buf, bufsiz, prefix); + _Py_END_SUPPRESS_IPH + if (result == EINVAL) { + Py_FatalError("invalid argument during ._pth processing"); + } else if (result == ERANGE) { + Py_FatalError("buffer overflow during ._pth processing"); + } + wchar_t *b = &buf[usedsiz]; join(b, wline); PyMem_RawFree(wline); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Oct 27 17:29:35 2016 From: python-checkins at python.org (steve.dower) Date: Thu, 27 Oct 2016 21:29:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTIy?= =?utf-8?q?=3A_Fixes_mishandled_buffer_reallocation_in_getpathp=2Ec?= Message-ID: <20161027212935.27249.41645.77932B45@psf.io> https://hg.python.org/cpython/rev/eea669163131 changeset: 104762:eea669163131 branch: 3.6 parent: 104760:dfda2f33fd08 user: Steve Dower date: Thu Oct 27 14:28:07 2016 -0700 summary: Issue #28522: Fixes mishandled buffer reallocation in getpathp.c files: Lib/test/test_site.py | 52 +++++++++++++++++++++++++++++++ Misc/NEWS | 5 ++ PC/getpathp.c | 19 ++++++++-- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -488,6 +488,58 @@ 'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()") + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") + def test_underpth_nosite_file(self): + _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + try: + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + with open(_pth_file, 'w') as f: + print('fake-path-name', file=f) + # Ensure the generated path is very long so that buffer + # resizing in getpathp.c is exercised + for _ in range(200): + print(libpath, file=f) + print('# comment', file=f) + + env = os.environ.copy() + env['PYTHONPATH'] = 'from-env' + rc = subprocess.call([sys.executable, '-c', + 'import sys; sys.exit(sys.flags.no_site and ' + 'len(sys.path) > 200 and ' + '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( + os.path.join(sys.prefix, 'fake-path-name'), + libpath, + os.path.join(sys.prefix, 'from-env'), + )], env=env) + self.assertEqual(rc, 0) + finally: + os.unlink(_pth_file) + + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") + def test_underpth_file(self): + _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + try: + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + with open(_pth_file, 'w') as f: + print('fake-path-name', file=f) + for _ in range(200): + print(libpath, file=f) + print('# comment', file=f) + print('import site', file=f) + + env = os.environ.copy() + env['PYTHONPATH'] = 'from-env' + rc = subprocess.call([sys.executable, '-c', + 'import sys; sys.exit(not sys.flags.no_site and ' + '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( + os.path.join(sys.prefix, 'fake-path-name'), + libpath, + os.path.join(sys.prefix, 'from-env'), + )], env=env) + self.assertEqual(rc, 0) + finally: + os.unlink(_pth_file) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,11 @@ threadpool executor. Initial patch by Hans Lawrenz. +Windows +------- + +- Issue #28522: Fixes mishandled buffer reallocation in getpathp.c + Build ----- diff --git a/PC/getpathp.c b/PC/getpathp.c --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -581,7 +581,8 @@ wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1); wline[wn] = '\0'; - while (wn + prefixlen + 4 > bufsiz) { + size_t usedsiz = wcslen(buf); + while (usedsiz + wn + prefixlen + 4 > bufsiz) { bufsiz += MAXPATHLEN; buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t)); if (!buf) { @@ -590,11 +591,21 @@ } } - if (buf[0]) + if (usedsiz) { wcscat_s(buf, bufsiz, L";"); + usedsiz += 1; + } - wchar_t *b = &buf[wcslen(buf)]; - wcscat_s(buf, bufsiz, prefix); + errno_t result; + _Py_BEGIN_SUPPRESS_IPH + result = wcscat_s(buf, bufsiz, prefix); + _Py_END_SUPPRESS_IPH + if (result == EINVAL) { + Py_FatalError("invalid argument during ._pth processing"); + } else if (result == ERANGE) { + Py_FatalError("buffer overflow during ._pth processing"); + } + wchar_t *b = &buf[usedsiz]; join(b, wline); PyMem_RawFree(wline); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 02:19:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 06:19:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MzUz?= =?utf-8?q?=3A_Make_test=5Fos=2EWalkTests=2Etest=5Fwalk=5Fbad=5Fdir_stable?= =?utf-8?q?=2E?= Message-ID: <20161028061944.21936.33825.0D7D3F09@psf.io> https://hg.python.org/cpython/rev/655510dd46fd changeset: 104764:655510dd46fd branch: 3.5 parent: 104758:a1aef5f84142 user: Serhiy Storchaka date: Fri Oct 28 09:17:38 2016 +0300 summary: Issue #28353: Make test_os.WalkTests.test_walk_bad_dir stable. files: Lib/test/test_os.py | 25 +++++++++++++++---------- 1 files changed, 15 insertions(+), 10 deletions(-) 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 @@ -980,16 +980,21 @@ errors = [] walk_it = self.walk(self.walk_path, onerror=errors.append) root, dirs, files = next(walk_it) - self.assertFalse(errors) - dir1 = dirs[0] - dir1new = dir1 + '.new' - os.rename(os.path.join(root, dir1), os.path.join(root, dir1new)) - roots = [r for r, d, f in walk_it] - self.assertTrue(errors) - self.assertNotIn(os.path.join(root, dir1), roots) - self.assertNotIn(os.path.join(root, dir1new), roots) - for dir2 in dirs[1:]: - self.assertIn(os.path.join(root, dir2), roots) + self.assertEqual(errors, []) + dir1 = 'SUB1' + path1 = os.path.join(root, dir1) + path1new = os.path.join(root, dir1 + '.new') + os.rename(path1, path1new) + try: + roots = [r for r, d, f in walk_it] + self.assertTrue(errors) + self.assertNotIn(path1, roots) + self.assertNotIn(path1new, roots) + for dir2 in dirs: + if dir2 != dir1: + self.assertIn(os.path.join(root, dir2), roots) + finally: + os.rename(path1new, path1) @unittest.skipUnless(hasattr(os, 'fwalk'), "Test needs os.fwalk()") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 02:19:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 06:19:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328353=3A_Make_test=5Fos=2EWalkTests=2Etest=5Fwalk=5Fb?= =?utf-8?q?ad=5Fdir_stable=2E?= Message-ID: <20161028061944.55516.73773.59C77ACC@psf.io> https://hg.python.org/cpython/rev/df28e536f19d changeset: 104765:df28e536f19d branch: 3.6 parent: 104762:eea669163131 parent: 104764:655510dd46fd user: Serhiy Storchaka date: Fri Oct 28 09:18:30 2016 +0300 summary: Issue #28353: Make test_os.WalkTests.test_walk_bad_dir stable. files: Lib/test/test_os.py | 25 +++++++++++++++---------- 1 files changed, 15 insertions(+), 10 deletions(-) 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 @@ -989,16 +989,21 @@ errors = [] walk_it = self.walk(self.walk_path, onerror=errors.append) root, dirs, files = next(walk_it) - self.assertFalse(errors) - dir1 = dirs[0] - dir1new = dir1 + '.new' - os.rename(os.path.join(root, dir1), os.path.join(root, dir1new)) - roots = [r for r, d, f in walk_it] - self.assertTrue(errors) - self.assertNotIn(os.path.join(root, dir1), roots) - self.assertNotIn(os.path.join(root, dir1new), roots) - for dir2 in dirs[1:]: - self.assertIn(os.path.join(root, dir2), roots) + self.assertEqual(errors, []) + dir1 = 'SUB1' + path1 = os.path.join(root, dir1) + path1new = os.path.join(root, dir1 + '.new') + os.rename(path1, path1new) + try: + roots = [r for r, d, f in walk_it] + self.assertTrue(errors) + self.assertNotIn(path1, roots) + self.assertNotIn(path1new, roots) + for dir2 in dirs: + if dir2 != dir1: + self.assertIn(os.path.join(root, dir2), roots) + finally: + os.rename(path1new, path1) @unittest.skipUnless(hasattr(os, 'fwalk'), "Test needs os.fwalk()") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 02:19:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 06:19:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328353=3A_Make_test=5Fos=2EWalkTests=2Etest=5Fwa?= =?utf-8?q?lk=5Fbad=5Fdir_stable=2E?= Message-ID: <20161028061944.55684.33361.51E54338@psf.io> https://hg.python.org/cpython/rev/aa891d13e1cf changeset: 104766:aa891d13e1cf parent: 104763:72e64fc8746b parent: 104765:df28e536f19d user: Serhiy Storchaka date: Fri Oct 28 09:19:19 2016 +0300 summary: Issue #28353: Make test_os.WalkTests.test_walk_bad_dir stable. files: Lib/test/test_os.py | 25 +++++++++++++++---------- 1 files changed, 15 insertions(+), 10 deletions(-) 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 @@ -989,16 +989,21 @@ errors = [] walk_it = self.walk(self.walk_path, onerror=errors.append) root, dirs, files = next(walk_it) - self.assertFalse(errors) - dir1 = dirs[0] - dir1new = dir1 + '.new' - os.rename(os.path.join(root, dir1), os.path.join(root, dir1new)) - roots = [r for r, d, f in walk_it] - self.assertTrue(errors) - self.assertNotIn(os.path.join(root, dir1), roots) - self.assertNotIn(os.path.join(root, dir1new), roots) - for dir2 in dirs[1:]: - self.assertIn(os.path.join(root, dir2), roots) + self.assertEqual(errors, []) + dir1 = 'SUB1' + path1 = os.path.join(root, dir1) + path1new = os.path.join(root, dir1 + '.new') + os.rename(path1, path1new) + try: + roots = [r for r, d, f in walk_it] + self.assertTrue(errors) + self.assertNotIn(path1, roots) + self.assertNotIn(path1new, roots) + for dir2 in dirs: + if dir2 != dir1: + self.assertIn(os.path.join(root, dir2), roots) + finally: + os.rename(path1new, path1) @unittest.skipUnless(hasattr(os, 'fwalk'), "Test needs os.fwalk()") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:22:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 09:22:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Fixed_possible_NULL_decrefing=2E?= Message-ID: <20161028092227.23226.8178.485723F5@psf.io> https://hg.python.org/cpython/rev/f8eb203415c8 changeset: 104769:f8eb203415c8 branch: 3.6 parent: 104765:df28e536f19d parent: 104767:695cea018ba9 user: Serhiy Storchaka date: Fri Oct 28 12:16:21 2016 +0300 summary: Fixed possible NULL decrefing. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1777,7 +1777,7 @@ PyErr_NormalizeException(&exc, &val, &tb); *(ev->exc_type) = exc; *(ev->exc_val) = val; - Py_DECREF(tb); + Py_XDECREF(tb); } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:22:26 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 09:22:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Fixed_possible?= =?utf-8?q?_NULL_decrefing=2E?= Message-ID: <20161028092226.22022.66710.BAE9AD68@psf.io> https://hg.python.org/cpython/rev/695cea018ba9 changeset: 104767:695cea018ba9 branch: 3.5 parent: 104764:655510dd46fd user: Serhiy Storchaka date: Fri Oct 28 12:14:34 2016 +0300 summary: Fixed possible NULL decrefing. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1779,7 +1779,7 @@ PyErr_NormalizeException(&exc, &val, &tb); *(ev->exc_type) = exc; *(ev->exc_val) = val; - Py_DECREF(tb); + Py_XDECREF(tb); } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:22:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 09:22:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fixed_possible?= =?utf-8?q?_NULL_decrefing=2E?= Message-ID: <20161028092227.41054.9544.4C902F14@psf.io> https://hg.python.org/cpython/rev/27af988f5623 changeset: 104768:27af988f5623 branch: 2.7 parent: 104759:8a564ab1d208 user: Serhiy Storchaka date: Fri Oct 28 12:14:34 2016 +0300 summary: Fixed possible NULL decrefing. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1874,7 +1874,7 @@ PyErr_NormalizeException(&exc, &val, &tb); *(ev->exc_type) = exc; *(ev->exc_val) = val; - Py_DECREF(tb); + Py_XDECREF(tb); } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:22:27 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 28 Oct 2016 09:22:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Fixed_possible_NULL_decrefing=2E?= Message-ID: <20161028092227.40780.7808.DA080ECA@psf.io> https://hg.python.org/cpython/rev/16ea07d420b8 changeset: 104770:16ea07d420b8 parent: 104766:aa891d13e1cf parent: 104769:f8eb203415c8 user: Serhiy Storchaka date: Fri Oct 28 12:17:17 2016 +0300 summary: Fixed possible NULL decrefing. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1777,7 +1777,7 @@ PyErr_NormalizeException(&exc, &val, &tb); *(ev->exc_type) = exc; *(ev->exc_val) = val; - Py_DECREF(tb); + Py_XDECREF(tb); } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:41:33 2016 From: python-checkins at python.org (xavier.degaye) Date: Fri, 28 Oct 2016 09:41:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgaGVhZHMu?= Message-ID: <20161028094133.76831.81069.659D146B@psf.io> https://hg.python.org/cpython/rev/57aac8abb437 changeset: 104773:57aac8abb437 parent: 104772:28205c4cf20b parent: 104770:16ea07d420b8 user: Xavier de Gaye date: Fri Oct 28 11:37:17 2016 +0200 summary: Merge heads. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1777,7 +1777,7 @@ PyErr_NormalizeException(&exc, &val, &tb); *(ev->exc_type) = exc; *(ev->exc_val) = val; - Py_DECREF(tb); + Py_XDECREF(tb); } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:41:33 2016 From: python-checkins at python.org (xavier.degaye) Date: Fri, 28 Oct 2016 09:41:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy42IC0+IDMuNik6?= =?utf-8?q?_Merge_heads=2E?= Message-ID: <20161028094133.40945.66469.1ECC162D@psf.io> https://hg.python.org/cpython/rev/763e8703cf2b changeset: 104774:763e8703cf2b branch: 3.6 parent: 104771:86577b7100a4 parent: 104769:f8eb203415c8 user: Xavier de Gaye date: Fri Oct 28 11:40:47 2016 +0200 summary: Merge heads. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1777,7 +1777,7 @@ PyErr_NormalizeException(&exc, &val, &tb); *(ev->exc_type) = exc; *(ev->exc_val) = val; - Py_DECREF(tb); + Py_XDECREF(tb); } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:41:33 2016 From: python-checkins at python.org (xavier.degaye) Date: Fri, 28 Oct 2016 09:41:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MDQ2?= =?utf-8?q?=3A_Fix_the_removal_of_the_sysconfigdata_module?= Message-ID: <20161028094132.58618.68939.09E7C01A@psf.io> https://hg.python.org/cpython/rev/86577b7100a4 changeset: 104771:86577b7100a4 branch: 3.6 parent: 104765:df28e536f19d user: Xavier de Gaye date: Fri Oct 28 11:22:05 2016 +0200 summary: Issue #28046: Fix the removal of the sysconfigdata module from lib-dynload on install. files: Makefile.pre.in | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1302,8 +1302,6 @@ done $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \ $(DESTDIR)$(LIBDEST); \ - echo $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS).py \ - $(LIBDEST) $(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt if test -d $(DESTDIR)$(LIBDEST)/distutils/tests; then \ $(INSTALL_DATA) $(srcdir)/Modules/xxmodule.c \ @@ -1437,7 +1435,7 @@ --install-scripts=$(BINDIR) \ --install-platlib=$(DESTSHARED) \ --root=$(DESTDIR)/ - -rm $(DESTDIR)$(DESTSHARED)/_sysconfigdata_$(ABIFLAGS).py + -rm $(DESTDIR)$(DESTSHARED)/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py -rm -r $(DESTDIR)$(DESTSHARED)/__pycache__ # Here are a couple of targets for MacOSX again, to install a full -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 05:41:33 2016 From: python-checkins at python.org (xavier.degaye) Date: Fri, 28 Oct 2016 09:41:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328046=3A_Merge_with_3=2E6=2E?= Message-ID: <20161028094133.26145.62149.075084AB@psf.io> https://hg.python.org/cpython/rev/28205c4cf20b changeset: 104772:28205c4cf20b parent: 104766:aa891d13e1cf parent: 104771:86577b7100a4 user: Xavier de Gaye date: Fri Oct 28 11:23:24 2016 +0200 summary: Issue #28046: Merge with 3.6. files: Makefile.pre.in | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1302,8 +1302,6 @@ done $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \ $(DESTDIR)$(LIBDEST); \ - echo $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS).py \ - $(LIBDEST) $(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt if test -d $(DESTDIR)$(LIBDEST)/distutils/tests; then \ $(INSTALL_DATA) $(srcdir)/Modules/xxmodule.c \ @@ -1437,7 +1435,7 @@ --install-scripts=$(BINDIR) \ --install-platlib=$(DESTSHARED) \ --root=$(DESTDIR)/ - -rm $(DESTDIR)$(DESTSHARED)/_sysconfigdata_$(ABIFLAGS).py + -rm $(DESTDIR)$(DESTSHARED)/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py -rm -r $(DESTDIR)$(DESTSHARED)/__pycache__ # Here are a couple of targets for MacOSX again, to install a full -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Fri Oct 28 11:24:47 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 28 Oct 2016 16:24:47 +0100 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-28 Message-ID: Results for project Python 2.7, build date 2016-10-28 02:47:31 +0000 commit: 8a564ab1d208 previous commit: 5a1edf5701f1 revision date: 2016-10-27 19:47:08 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% -0.61% 4.56% 6.90% :-) pybench 0.17% 0.04% 5.82% 4.03% :-( regex_v8 0.66% -0.11% -2.21% 10.78% :-) nbody 0.07% 0.00% 7.96% 5.46% :-) json_dump_v2 0.27% -0.01% 2.64% 8.64% :-| normal_startup 1.38% 0.50% 0.23% 2.02% :-) ssbench 0.09% 0.42% 2.39% 1.45% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-28/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Fri Oct 28 11:25:21 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Fri, 28 Oct 2016 16:25:21 +0100 Subject: [Python-checkins] UGLY Benchmark Results for Python Default 2016-10-28 Message-ID: Results for project Python default, build date 2016-10-28 02:01:23 +0000 commit: 72e64fc8746b previous commit: 849826a900d2 revision date: 2016-10-27 21:29:13 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.24% -0.80% 4.37% 16.38% :-) pybench 0.24% 0.64% 5.91% 4.21% :-| regex_v8 3.99% 1.21% -0.45% 1.30% :-) nbody 0.12% -0.09% 3.56% 3.05% :-( json_dump_v2 0.32% -1.25% -11.75% 15.34% :-| normal_startup 1.01% -0.13% 0.74% 6.43% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/ugly-benchmark-results-for-python-default-2016-10-28/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Fri Oct 28 12:53:34 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 28 Oct 2016 16:53:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg1NDQp?= Message-ID: <20161028165334.25980.73753.8994A1F3@psf.io> https://hg.python.org/cpython/rev/8059289b55c1 changeset: 104776:8059289b55c1 parent: 104773:57aac8abb437 parent: 104775:db5ae4f6df8a user: Yury Selivanov date: Fri Oct 28 12:53:29 2016 -0400 summary: Merge 3.6 (issue #28544) files: Lib/asyncio/base_events.py | 2 +- Lib/asyncio/base_futures.py | 70 + Lib/asyncio/base_tasks.py | 76 + Lib/asyncio/coroutines.py | 4 +- Lib/asyncio/futures.py | 91 +- Lib/asyncio/tasks.py | 80 +- Lib/test/test_asyncio/test_tasks.py | 445 ++- Modules/_asynciomodule.c | 1984 ++++++++++++-- Modules/clinic/_asynciomodule.c.h | 520 +++ 9 files changed, 2715 insertions(+), 557 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -57,7 +57,7 @@ def _format_handle(handle): cb = handle._callback - if inspect.ismethod(cb) and isinstance(cb.__self__, tasks.Task): + if isinstance(getattr(cb, '__self__', None), tasks.Task): # format the task return repr(cb.__self__) else: diff --git a/Lib/asyncio/base_futures.py b/Lib/asyncio/base_futures.py new file mode 100644 --- /dev/null +++ b/Lib/asyncio/base_futures.py @@ -0,0 +1,70 @@ +__all__ = [] + +import concurrent.futures._base +import reprlib + +from . import events + +Error = concurrent.futures._base.Error +CancelledError = concurrent.futures.CancelledError +TimeoutError = concurrent.futures.TimeoutError + + +class InvalidStateError(Error): + """The operation is not allowed in this state.""" + + +# States for Future. +_PENDING = 'PENDING' +_CANCELLED = 'CANCELLED' +_FINISHED = 'FINISHED' + + +def isfuture(obj): + """Check for a Future. + + This returns True when obj is a Future instance or is advertising + itself as duck-type compatible by setting _asyncio_future_blocking. + See comment in Future for more details. + """ + return getattr(obj, '_asyncio_future_blocking', None) is not None + + +def _format_callbacks(cb): + """helper function for Future.__repr__""" + size = len(cb) + if not size: + cb = '' + + def format_cb(callback): + return events._format_callback_source(callback, ()) + + if size == 1: + cb = format_cb(cb[0]) + elif size == 2: + cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) + elif size > 2: + cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), + size - 2, + format_cb(cb[-1])) + return 'cb=[%s]' % cb + + +def _future_repr_info(future): + # (Future) -> str + """helper function for Future.__repr__""" + info = [future._state.lower()] + if future._state == _FINISHED: + if future._exception is not None: + info.append('exception={!r}'.format(future._exception)) + else: + # use reprlib to limit the length of the output, especially + # for very long strings + result = reprlib.repr(future._result) + info.append('result={}'.format(result)) + if future._callbacks: + info.append(_format_callbacks(future._callbacks)) + if future._source_traceback: + frame = future._source_traceback[-1] + info.append('created at %s:%s' % (frame[0], frame[1])) + return info diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py new file mode 100644 --- /dev/null +++ b/Lib/asyncio/base_tasks.py @@ -0,0 +1,76 @@ +import linecache +import traceback + +from . import base_futures +from . import coroutines + + +def _task_repr_info(task): + info = base_futures._future_repr_info(task) + + if task._must_cancel: + # replace status + info[0] = 'cancelling' + + coro = coroutines._format_coroutine(task._coro) + info.insert(1, 'coro=<%s>' % coro) + + if task._fut_waiter is not None: + info.insert(2, 'wait_for=%r' % task._fut_waiter) + return info + + +def _task_get_stack(task, limit): + frames = [] + try: + # 'async def' coroutines + f = task._coro.cr_frame + except AttributeError: + f = task._coro.gi_frame + if f is not None: + while f is not None: + if limit is not None: + if limit <= 0: + break + limit -= 1 + frames.append(f) + f = f.f_back + frames.reverse() + elif task._exception is not None: + tb = task._exception.__traceback__ + while tb is not None: + if limit is not None: + if limit <= 0: + break + limit -= 1 + frames.append(tb.tb_frame) + tb = tb.tb_next + return frames + + +def _task_print_stack(task, limit, file): + extracted_list = [] + checked = set() + for f in task.get_stack(limit=limit): + lineno = f.f_lineno + co = f.f_code + filename = co.co_filename + name = co.co_name + if filename not in checked: + checked.add(filename) + linecache.checkcache(filename) + line = linecache.getline(filename, lineno, f.f_globals) + extracted_list.append((filename, lineno, name, line)) + exc = task._exception + if not extracted_list: + print('No stack for %r' % task, file=file) + elif exc is not None: + print('Traceback for %r (most recent call last):' % task, + file=file) + else: + print('Stack for %r (most recent call last):' % task, + file=file) + traceback.print_list(extracted_list, file=file) + if exc is not None: + for line in traceback.format_exception_only(exc.__class__, exc): + print(line, file=file, end='') diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -11,7 +11,7 @@ from . import compat from . import events -from . import futures +from . import base_futures from .log import logger @@ -204,7 +204,7 @@ @functools.wraps(func) def coro(*args, **kw): res = func(*args, **kw) - if (futures.isfuture(res) or inspect.isgenerator(res) or + if (base_futures.isfuture(res) or inspect.isgenerator(res) or isinstance(res, CoroWrapper)): res = yield from res elif _AwaitableABC is not None: diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -1,35 +1,32 @@ """A Future class similar to the one in PEP 3148.""" -__all__ = ['CancelledError', 'TimeoutError', - 'InvalidStateError', - 'Future', 'wrap_future', 'isfuture' - ] +__all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', + 'Future', 'wrap_future', 'isfuture'] -import concurrent.futures._base +import concurrent.futures import logging -import reprlib import sys import traceback +from . import base_futures from . import compat from . import events -# States for Future. -_PENDING = 'PENDING' -_CANCELLED = 'CANCELLED' -_FINISHED = 'FINISHED' -Error = concurrent.futures._base.Error -CancelledError = concurrent.futures.CancelledError -TimeoutError = concurrent.futures.TimeoutError +CancelledError = base_futures.CancelledError +InvalidStateError = base_futures.InvalidStateError +TimeoutError = base_futures.TimeoutError +isfuture = base_futures.isfuture + + +_PENDING = base_futures._PENDING +_CANCELLED = base_futures._CANCELLED +_FINISHED = base_futures._FINISHED + STACK_DEBUG = logging.DEBUG - 1 # heavy-duty debugging -class InvalidStateError(Error): - """The operation is not allowed in this state.""" - - class _TracebackLogger: """Helper to log a traceback upon destruction if not cleared. @@ -110,56 +107,6 @@ self.loop.call_exception_handler({'message': msg}) -def isfuture(obj): - """Check for a Future. - - This returns True when obj is a Future instance or is advertising - itself as duck-type compatible by setting _asyncio_future_blocking. - See comment in Future for more details. - """ - return getattr(obj, '_asyncio_future_blocking', None) is not None - - -def _format_callbacks(cb): - """helper function for Future.__repr__""" - size = len(cb) - if not size: - cb = '' - - def format_cb(callback): - return events._format_callback_source(callback, ()) - - if size == 1: - cb = format_cb(cb[0]) - elif size == 2: - cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) - elif size > 2: - cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), - size-2, - format_cb(cb[-1])) - return 'cb=[%s]' % cb - - -def _future_repr_info(future): - # (Future) -> str - """helper function for Future.__repr__""" - info = [future._state.lower()] - if future._state == _FINISHED: - if future._exception is not None: - info.append('exception={!r}'.format(future._exception)) - else: - # use reprlib to limit the length of the output, especially - # for very long strings - result = reprlib.repr(future._result) - info.append('result={}'.format(result)) - if future._callbacks: - info.append(_format_callbacks(future._callbacks)) - if future._source_traceback: - frame = future._source_traceback[-1] - info.append('created at %s:%s' % (frame[0], frame[1])) - return info - - class Future: """This class is *almost* compatible with concurrent.futures.Future. @@ -212,7 +159,7 @@ if self._loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) - _repr_info = _future_repr_info + _repr_info = base_futures._future_repr_info def __repr__(self): return '<%s %s>' % (self.__class__.__name__, ' '.join(self._repr_info())) @@ -247,10 +194,10 @@ if self._state != _PENDING: return False self._state = _CANCELLED - self.__schedule_callbacks() + self._schedule_callbacks() return True - def __schedule_callbacks(self): + def _schedule_callbacks(self): """Internal: Ask the event loop to call all callbacks. The callbacks are scheduled to be called as soon as possible. Also @@ -352,7 +299,7 @@ raise InvalidStateError('{}: {!r}'.format(self._state, self)) self._result = result self._state = _FINISHED - self.__schedule_callbacks() + self._schedule_callbacks() def set_exception(self, exception): """Mark the future done and set an exception. @@ -369,7 +316,7 @@ "and cannot be raised into a Future") self._exception = exception self._state = _FINISHED - self.__schedule_callbacks() + self._schedule_callbacks() if compat.PY34: self._log_traceback = True else: diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -9,11 +9,10 @@ import concurrent.futures import functools import inspect -import linecache -import traceback import warnings import weakref +from . import base_tasks from . import compat from . import coroutines from . import events @@ -93,18 +92,7 @@ futures.Future.__del__(self) def _repr_info(self): - info = super()._repr_info() - - if self._must_cancel: - # replace status - info[0] = 'cancelling' - - coro = coroutines._format_coroutine(self._coro) - info.insert(1, 'coro=<%s>' % coro) - - if self._fut_waiter is not None: - info.insert(2, 'wait_for=%r' % self._fut_waiter) - return info + return base_tasks._task_repr_info(self) def get_stack(self, *, limit=None): """Return the list of stack frames for this task's coroutine. @@ -127,31 +115,7 @@ For reasons beyond our control, only one stack frame is returned for a suspended coroutine. """ - frames = [] - try: - # 'async def' coroutines - f = self._coro.cr_frame - except AttributeError: - f = self._coro.gi_frame - if f is not None: - while f is not None: - if limit is not None: - if limit <= 0: - break - limit -= 1 - frames.append(f) - f = f.f_back - frames.reverse() - elif self._exception is not None: - tb = self._exception.__traceback__ - while tb is not None: - if limit is not None: - if limit <= 0: - break - limit -= 1 - frames.append(tb.tb_frame) - tb = tb.tb_next - return frames + return base_tasks._task_get_stack(self, limit) def print_stack(self, *, limit=None, file=None): """Print the stack or traceback for this task's coroutine. @@ -162,31 +126,7 @@ to which the output is written; by default output is written to sys.stderr. """ - extracted_list = [] - checked = set() - for f in self.get_stack(limit=limit): - lineno = f.f_lineno - co = f.f_code - filename = co.co_filename - name = co.co_name - if filename not in checked: - checked.add(filename) - linecache.checkcache(filename) - line = linecache.getline(filename, lineno, f.f_globals) - extracted_list.append((filename, lineno, name, line)) - exc = self._exception - if not extracted_list: - print('No stack for %r' % self, file=file) - elif exc is not None: - print('Traceback for %r (most recent call last):' % self, - file=file) - else: - print('Stack for %r (most recent call last):' % self, - file=file) - traceback.print_list(extracted_list, file=file) - if exc is not None: - for line in traceback.format_exception_only(exc.__class__, exc): - print(line, file=file, end='') + return base_tasks._task_print_stack(self, limit, file) def cancel(self): """Request that this task cancel itself. @@ -316,6 +256,18 @@ self = None # Needed to break cycles when an exception occurs. +_PyTask = Task + + +try: + import _asyncio +except ImportError: + pass +else: + # _CTask is needed for tests. + Task = _CTask = _asyncio.Task + + # wait() and as_completed() similar to those in PEP 3148. FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1,5 +1,6 @@ """Tests for tasks.py.""" +import collections import contextlib import functools import io @@ -14,6 +15,8 @@ import asyncio from asyncio import coroutines +from asyncio import futures +from asyncio import tasks from asyncio import test_utils try: from test import support @@ -72,14 +75,25 @@ pass -class TaskTests(test_utils.TestCase): +class BaseTaskTests: + + Task = None + Future = None + + def new_task(self, loop, coro): + return self.__class__.Task(coro, loop=loop) + + def new_future(self, loop): + return self.__class__.Future(loop=loop) def setUp(self): self.loop = self.new_test_loop() + self.loop.set_task_factory(self.new_task) + self.loop.create_future = lambda: self.new_future(self.loop) def test_other_loop_future(self): other_loop = asyncio.new_event_loop() - fut = asyncio.Future(loop=other_loop) + fut = self.new_future(other_loop) @asyncio.coroutine def run(fut): @@ -107,7 +121,7 @@ @asyncio.coroutine def notmuch(): return 'ok' - t = asyncio.Task(notmuch(), loop=self.loop) + t = self.new_task(self.loop, notmuch()) self.loop.run_until_complete(t) self.assertTrue(t.done()) self.assertEqual(t.result(), 'ok') @@ -115,7 +129,7 @@ loop = asyncio.new_event_loop() self.set_event_loop(loop) - t = asyncio.Task(notmuch(), loop=loop) + t = self.new_task(loop, notmuch()) self.assertIs(t._loop, loop) loop.run_until_complete(t) loop.close() @@ -138,7 +152,7 @@ loop.close() def test_ensure_future_future(self): - f_orig = asyncio.Future(loop=self.loop) + f_orig = self.new_future(self.loop) f_orig.set_result('ko') f = asyncio.ensure_future(f_orig) @@ -162,7 +176,7 @@ @asyncio.coroutine def notmuch(): return 'ok' - t_orig = asyncio.Task(notmuch(), loop=self.loop) + t_orig = self.new_task(self.loop, notmuch()) t = asyncio.ensure_future(t_orig) self.loop.run_until_complete(t) self.assertTrue(t.done()) @@ -203,7 +217,7 @@ asyncio.ensure_future('ok') def test_async_warning(self): - f = asyncio.Future(loop=self.loop) + f = self.new_future(self.loop) with self.assertWarnsRegex(DeprecationWarning, 'function is deprecated, use ensure_'): self.assertIs(f, asyncio.async(f)) @@ -250,8 +264,8 @@ # test coroutine function self.assertEqual(notmuch.__name__, 'notmuch') if PY35: - self.assertEqual(notmuch.__qualname__, - 'TaskTests.test_task_repr..notmuch') + self.assertRegex(notmuch.__qualname__, + r'\w+.test_task_repr..notmuch') self.assertEqual(notmuch.__module__, __name__) filename, lineno = test_utils.get_function_source(notmuch) @@ -260,7 +274,7 @@ # test coroutine object gen = notmuch() if coroutines._DEBUG or PY35: - coro_qualname = 'TaskTests.test_task_repr..notmuch' + coro_qualname = 'BaseTaskTests.test_task_repr..notmuch' else: coro_qualname = 'notmuch' self.assertEqual(gen.__name__, 'notmuch') @@ -269,7 +283,7 @@ coro_qualname) # test pending Task - t = asyncio.Task(gen, loop=self.loop) + t = self.new_task(self.loop, gen) t.add_done_callback(Dummy()) coro = format_coroutine(coro_qualname, 'running', src, @@ -291,7 +305,7 @@ '' % coro) # test finished Task - t = asyncio.Task(notmuch(), loop=self.loop) + t = self.new_task(self.loop, notmuch()) self.loop.run_until_complete(t) coro = format_coroutine(coro_qualname, 'done', src, t._source_traceback) @@ -310,9 +324,9 @@ # test coroutine function self.assertEqual(notmuch.__name__, 'notmuch') if PY35: - self.assertEqual(notmuch.__qualname__, - 'TaskTests.test_task_repr_coro_decorator' - '..notmuch') + self.assertRegex(notmuch.__qualname__, + r'\w+.test_task_repr_coro_decorator' + r'\.\.notmuch') self.assertEqual(notmuch.__module__, __name__) # test coroutine object @@ -322,7 +336,7 @@ # function, as expected, and have a qualified name (__qualname__ # attribute). coro_name = 'notmuch' - coro_qualname = ('TaskTests.test_task_repr_coro_decorator' + coro_qualname = ('BaseTaskTests.test_task_repr_coro_decorator' '..notmuch') else: # On Python < 3.5, generators inherit the name of the code, not of @@ -350,7 +364,7 @@ self.assertEqual(repr(gen), '' % coro) # test pending Task - t = asyncio.Task(gen, loop=self.loop) + t = self.new_task(self.loop, gen) t.add_done_callback(Dummy()) # format the coroutine object @@ -373,8 +387,8 @@ def wait_for(fut): return (yield from fut) - fut = asyncio.Future(loop=self.loop) - task = asyncio.Task(wait_for(fut), loop=self.loop) + fut = self.new_future(self.loop) + task = self.new_task(self.loop, wait_for(fut)) test_utils.run_briefly(self.loop) self.assertRegex(repr(task), '' % re.escape(repr(fut))) @@ -400,10 +414,11 @@ self.addCleanup(task._coro.close) coro_repr = repr(task._coro) - expected = ('.func(1)() running, ') - self.assertTrue(coro_repr.startswith(expected), - coro_repr) + expected = ( + r'\.func\(1\)\(\) running, ' + ) + self.assertRegex(coro_repr, expected) def test_task_basics(self): @asyncio.coroutine @@ -437,7 +452,7 @@ yield from asyncio.sleep(10.0, loop=loop) return 12 - t = asyncio.Task(task(), loop=loop) + t = self.new_task(loop, task()) loop.call_soon(t.cancel) with self.assertRaises(asyncio.CancelledError): loop.run_until_complete(t) @@ -452,7 +467,7 @@ yield return 12 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) # start coro t.cancel() self.assertRaises( @@ -462,14 +477,14 @@ self.assertFalse(t.cancel()) def test_cancel_inner_future(self): - f = asyncio.Future(loop=self.loop) + f = self.new_future(self.loop) @asyncio.coroutine def task(): yield from f return 12 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) # start task f.cancel() with self.assertRaises(asyncio.CancelledError): @@ -478,14 +493,14 @@ self.assertTrue(t.cancelled()) def test_cancel_both_task_and_inner_future(self): - f = asyncio.Future(loop=self.loop) + f = self.new_future(self.loop) @asyncio.coroutine def task(): yield from f return 12 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) f.cancel() @@ -499,8 +514,8 @@ self.assertTrue(t.cancelled()) def test_cancel_task_catching(self): - fut1 = asyncio.Future(loop=self.loop) - fut2 = asyncio.Future(loop=self.loop) + fut1 = self.new_future(self.loop) + fut2 = self.new_future(self.loop) @asyncio.coroutine def task(): @@ -510,7 +525,7 @@ except asyncio.CancelledError: return 42 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) self.assertIs(t._fut_waiter, fut1) # White-box test. fut1.set_result(None) @@ -523,9 +538,9 @@ self.assertFalse(t.cancelled()) def test_cancel_task_ignoring(self): - fut1 = asyncio.Future(loop=self.loop) - fut2 = asyncio.Future(loop=self.loop) - fut3 = asyncio.Future(loop=self.loop) + fut1 = self.new_future(self.loop) + fut2 = self.new_future(self.loop) + fut3 = self.new_future(self.loop) @asyncio.coroutine def task(): @@ -537,7 +552,7 @@ res = yield from fut3 return res - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) self.assertIs(t._fut_waiter, fut1) # White-box test. fut1.set_result(None) @@ -565,7 +580,7 @@ yield from asyncio.sleep(100, loop=loop) return 12 - t = asyncio.Task(task(), loop=loop) + t = self.new_task(loop, task()) self.assertRaises( asyncio.CancelledError, loop.run_until_complete, t) self.assertTrue(t.done()) @@ -598,7 +613,7 @@ if x == 2: loop.stop() - t = asyncio.Task(task(), loop=loop) + t = self.new_task(loop, task()) with self.assertRaises(RuntimeError) as cm: loop.run_until_complete(t) self.assertEqual(str(cm.exception), @@ -636,7 +651,7 @@ foo_running = False return 'done' - fut = asyncio.Task(foo(), loop=loop) + fut = self.new_task(loop, foo()) with self.assertRaises(asyncio.TimeoutError): loop.run_until_complete(asyncio.wait_for(fut, 0.1, loop=loop)) @@ -676,7 +691,7 @@ asyncio.set_event_loop(loop) try: - fut = asyncio.Task(foo(), loop=loop) + fut = self.new_task(loop, foo()) with self.assertRaises(asyncio.TimeoutError): loop.run_until_complete(asyncio.wait_for(fut, 0.01)) finally: @@ -695,7 +710,7 @@ loop = self.new_test_loop(gen) - fut = asyncio.Future(loop=loop) + fut = self.new_future(loop) task = asyncio.wait_for(fut, timeout=0.2, loop=loop) loop.call_later(0.1, fut.set_result, "ok") res = loop.run_until_complete(task) @@ -712,8 +727,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.15, loop=loop)) @asyncio.coroutine def foo(): @@ -722,12 +737,12 @@ self.assertEqual(pending, set()) return 42 - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertEqual(res, 42) self.assertAlmostEqual(0.15, loop.time()) # Doing it again should take no time and exercise a different path. - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) self.assertEqual(res, 42) @@ -742,8 +757,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.01, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.015, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.01, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.015, loop=loop)) @asyncio.coroutine def foo(): @@ -754,7 +769,7 @@ asyncio.set_event_loop(loop) res = loop.run_until_complete( - asyncio.Task(foo(), loop=loop)) + self.new_task(loop, foo())) self.assertEqual(res, 42) @@ -764,9 +779,9 @@ return s c = coro('test') - task = asyncio.Task( - asyncio.wait([c, c, coro('spam')], loop=self.loop), - loop=self.loop) + task =self.new_task( + self.loop, + asyncio.wait([c, c, coro('spam')], loop=self.loop)) done, pending = self.loop.run_until_complete(task) @@ -797,12 +812,12 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - task = asyncio.Task( + a = self.new_task(loop, asyncio.sleep(10.0, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + task = self.new_task( + loop, asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, - loop=loop), - loop=loop) + loop=loop)) done, pending = loop.run_until_complete(task) self.assertEqual({b}, done) @@ -829,12 +844,12 @@ yield yield - a = asyncio.Task(coro1(), loop=self.loop) - b = asyncio.Task(coro2(), loop=self.loop) - task = asyncio.Task( + a = self.new_task(self.loop, coro1()) + b = self.new_task(self.loop, coro2()) + task = self.new_task( + self.loop, asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, - loop=self.loop), - loop=self.loop) + loop=self.loop)) done, pending = self.loop.run_until_complete(task) self.assertEqual({a, b}, done) @@ -853,17 +868,17 @@ loop = self.new_test_loop(gen) # first_exception, task already has exception - a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(10.0, loop=loop)) @asyncio.coroutine def exc(): raise ZeroDivisionError('err') - b = asyncio.Task(exc(), loop=loop) - task = asyncio.Task( + b = self.new_task(loop, exc()) + task = self.new_task( + loop, asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, - loop=loop), - loop=loop) + loop=loop)) done, pending = loop.run_until_complete(task) self.assertEqual({b}, done) @@ -886,14 +901,14 @@ loop = self.new_test_loop(gen) # first_exception, exception during waiting - a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(10.0, loop=loop)) @asyncio.coroutine def exc(): yield from asyncio.sleep(0.01, loop=loop) raise ZeroDivisionError('err') - b = asyncio.Task(exc(), loop=loop) + b = self.new_task(loop, exc()) task = asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, loop=loop) @@ -917,14 +932,14 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) @asyncio.coroutine def sleeper(): yield from asyncio.sleep(0.15, loop=loop) raise ZeroDivisionError('really') - b = asyncio.Task(sleeper(), loop=loop) + b = self.new_task(loop, sleeper()) @asyncio.coroutine def foo(): @@ -934,10 +949,10 @@ errors = set(f for f in done if f.exception() is not None) self.assertEqual(len(errors), 1) - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) def test_wait_with_timeout(self): @@ -953,8 +968,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.15, loop=loop)) @asyncio.coroutine def foo(): @@ -963,7 +978,7 @@ self.assertEqual(done, set([a])) self.assertEqual(pending, set([b])) - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.11, loop.time()) # move forward to close generator @@ -983,8 +998,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.15, loop=loop)) done, pending = loop.run_until_complete( asyncio.wait([b, a], timeout=0.1, loop=loop)) @@ -1032,14 +1047,14 @@ values.append((yield from f)) return values - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) self.assertTrue('a' in res[:2]) self.assertTrue('b' in res[:2]) self.assertEqual(res[2], 'c') # Doing it again should take no time and exercise a different path. - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) def test_as_completed_with_timeout(self): @@ -1068,7 +1083,7 @@ values.append((2, exc)) return values - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertEqual(len(res), 2, res) self.assertEqual(res[0], (1, 'a')) self.assertEqual(res[1][0], 2) @@ -1096,7 +1111,7 @@ v = yield from f self.assertEqual(v, 'a') - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) def test_as_completed_reverse_wait(self): @@ -1156,7 +1171,7 @@ result.append((yield from f)) return result - fut = asyncio.Task(runner(), loop=self.loop) + fut = self.new_task(self.loop, runner()) self.loop.run_until_complete(fut) result = fut.result() self.assertEqual(set(result), {'ham', 'spam'}) @@ -1179,7 +1194,7 @@ res = yield from asyncio.sleep(dt/2, arg, loop=loop) return res - t = asyncio.Task(sleeper(0.1, 'yeah'), loop=loop) + t = self.new_task(loop, sleeper(0.1, 'yeah')) loop.run_until_complete(t) self.assertTrue(t.done()) self.assertEqual(t.result(), 'yeah') @@ -1194,8 +1209,7 @@ loop = self.new_test_loop(gen) - t = asyncio.Task(asyncio.sleep(10.0, 'yeah', loop=loop), - loop=loop) + t = self.new_task(loop, asyncio.sleep(10.0, 'yeah', loop=loop)) handle = None orig_call_later = loop.call_later @@ -1231,7 +1245,7 @@ @asyncio.coroutine def doit(): - sleeper = asyncio.Task(sleep(5000), loop=loop) + sleeper = self.new_task(loop, sleep(5000)) loop.call_later(0.1, sleeper.cancel) try: yield from sleeper @@ -1245,13 +1259,13 @@ self.assertAlmostEqual(0.1, loop.time()) def test_task_cancel_waiter_future(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) @asyncio.coroutine def coro(): yield from fut - task = asyncio.Task(coro(), loop=self.loop) + task = self.new_task(self.loop, coro()) test_utils.run_briefly(self.loop) self.assertIs(task._fut_waiter, fut) @@ -1268,7 +1282,7 @@ return 'ko' gen = notmuch() - task = asyncio.Task(gen, loop=self.loop) + task = self.new_task(self.loop, gen) task.set_result('ok') self.assertRaises(AssertionError, task._step) @@ -1304,7 +1318,7 @@ nonlocal result result = yield from fut - t = asyncio.Task(wait_for_future(), loop=self.loop) + t = self.new_task(self.loop, wait_for_future()) test_utils.run_briefly(self.loop) self.assertTrue(fut.cb_added) @@ -1320,7 +1334,7 @@ def notmutch(): raise BaseException() - task = asyncio.Task(notmutch(), loop=self.loop) + task = self.new_task(self.loop, notmutch()) self.assertRaises(BaseException, task._step) self.assertTrue(task.done()) @@ -1348,7 +1362,7 @@ except asyncio.CancelledError: raise base_exc - task = asyncio.Task(notmutch(), loop=loop) + task = self.new_task(loop, notmutch()) test_utils.run_briefly(loop) task.cancel() @@ -1376,7 +1390,7 @@ self.assertTrue(asyncio.iscoroutinefunction(fn2)) def test_yield_vs_yield_from(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) @asyncio.coroutine def wait_for_future(): @@ -1420,7 +1434,7 @@ self.assertEqual(res, 'test') def test_coroutine_non_gen_function_return_future(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) @asyncio.coroutine def func(): @@ -1430,49 +1444,53 @@ def coro(): fut.set_result('test') - t1 = asyncio.Task(func(), loop=self.loop) - t2 = asyncio.Task(coro(), loop=self.loop) + t1 = self.new_task(self.loop, func()) + t2 = self.new_task(self.loop, coro()) res = self.loop.run_until_complete(t1) self.assertEqual(res, 'test') self.assertIsNone(t2.result()) def test_current_task(self): - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) + Task = self.__class__.Task + + self.assertIsNone(Task.current_task(loop=self.loop)) @asyncio.coroutine def coro(loop): - self.assertTrue(asyncio.Task.current_task(loop=loop) is task) - - task = asyncio.Task(coro(self.loop), loop=self.loop) + self.assertTrue(Task.current_task(loop=loop) is task) + + task = self.new_task(self.loop, coro(self.loop)) self.loop.run_until_complete(task) - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) + self.assertIsNone(Task.current_task(loop=self.loop)) def test_current_task_with_interleaving_tasks(self): - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) - - fut1 = asyncio.Future(loop=self.loop) - fut2 = asyncio.Future(loop=self.loop) + Task = self.__class__.Task + + self.assertIsNone(Task.current_task(loop=self.loop)) + + fut1 = self.new_future(self.loop) + fut2 = self.new_future(self.loop) @asyncio.coroutine def coro1(loop): - self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) + self.assertTrue(Task.current_task(loop=loop) is task1) yield from fut1 - self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) + self.assertTrue(Task.current_task(loop=loop) is task1) fut2.set_result(True) @asyncio.coroutine def coro2(loop): - self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) + self.assertTrue(Task.current_task(loop=loop) is task2) fut1.set_result(True) yield from fut2 - self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) - - task1 = asyncio.Task(coro1(self.loop), loop=self.loop) - task2 = asyncio.Task(coro2(self.loop), loop=self.loop) + self.assertTrue(Task.current_task(loop=loop) is task2) + + task1 = self.new_task(self.loop, coro1(self.loop)) + task2 = self.new_task(self.loop, coro2(self.loop)) self.loop.run_until_complete(asyncio.wait((task1, task2), loop=self.loop)) - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) + self.assertIsNone(Task.current_task(loop=self.loop)) # Some thorough tests for cancellation propagation through # coroutines, tasks and wait(). @@ -1480,7 +1498,7 @@ def test_yield_future_passes_cancel(self): # Cancelling outer() cancels inner() cancels waiter. proof = 0 - waiter = asyncio.Future(loop=self.loop) + waiter = self.new_future(self.loop) @asyncio.coroutine def inner(): @@ -1514,7 +1532,7 @@ # Cancelling outer() makes wait() return early, leaves inner() # running. proof = 0 - waiter = asyncio.Future(loop=self.loop) + waiter = self.new_future(self.loop) @asyncio.coroutine def inner(): @@ -1538,14 +1556,14 @@ self.assertEqual(proof, 1) def test_shield_result(self): - inner = asyncio.Future(loop=self.loop) + inner = self.new_future(self.loop) outer = asyncio.shield(inner) inner.set_result(42) res = self.loop.run_until_complete(outer) self.assertEqual(res, 42) def test_shield_exception(self): - inner = asyncio.Future(loop=self.loop) + inner = self.new_future(self.loop) outer = asyncio.shield(inner) test_utils.run_briefly(self.loop) exc = RuntimeError('expected') @@ -1554,7 +1572,7 @@ self.assertIs(outer.exception(), exc) def test_shield_cancel(self): - inner = asyncio.Future(loop=self.loop) + inner = self.new_future(self.loop) outer = asyncio.shield(inner) test_utils.run_briefly(self.loop) inner.cancel() @@ -1562,7 +1580,7 @@ self.assertTrue(outer.cancelled()) def test_shield_shortcut(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) fut.set_result(42) res = self.loop.run_until_complete(asyncio.shield(fut)) self.assertEqual(res, 42) @@ -1570,7 +1588,7 @@ def test_shield_effect(self): # Cancelling outer() does not affect inner(). proof = 0 - waiter = asyncio.Future(loop=self.loop) + waiter = self.new_future(self.loop) @asyncio.coroutine def inner(): @@ -1594,8 +1612,8 @@ self.assertEqual(proof, 1) def test_shield_gather(self): - child1 = asyncio.Future(loop=self.loop) - child2 = asyncio.Future(loop=self.loop) + child1 = self.new_future(self.loop) + child2 = self.new_future(self.loop) parent = asyncio.gather(child1, child2, loop=self.loop) outer = asyncio.shield(parent, loop=self.loop) test_utils.run_briefly(self.loop) @@ -1608,8 +1626,8 @@ self.assertEqual(parent.result(), [1, 2]) def test_gather_shield(self): - child1 = asyncio.Future(loop=self.loop) - child2 = asyncio.Future(loop=self.loop) + child1 = self.new_future(self.loop) + child2 = self.new_future(self.loop) inner1 = asyncio.shield(child1, loop=self.loop) inner2 = asyncio.shield(child2, loop=self.loop) parent = asyncio.gather(inner1, inner2, loop=self.loop) @@ -1625,7 +1643,7 @@ test_utils.run_briefly(self.loop) def test_as_completed_invalid_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) # as_completed() expects a list of futures, not a future instance self.assertRaises(TypeError, self.loop.run_until_complete, @@ -1636,7 +1654,7 @@ coro.close() def test_wait_invalid_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) # wait() expects a list of futures, not a future instance self.assertRaises(TypeError, self.loop.run_until_complete, @@ -1663,7 +1681,7 @@ yield from fut # A completed Future used to run the coroutine. - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) fut.set_result(None) # Call the coroutine. @@ -1697,15 +1715,15 @@ @asyncio.coroutine def t2(): - f = asyncio.Future(loop=self.loop) - asyncio.Task(t3(f), loop=self.loop) + f = self.new_future(self.loop) + self.new_task(self.loop, t3(f)) return (yield from f) @asyncio.coroutine def t3(f): f.set_result((1, 2, 3)) - task = asyncio.Task(t1(), loop=self.loop) + task = self.new_task(self.loop, t1()) val = self.loop.run_until_complete(task) self.assertEqual(val, (1, 2, 3)) @@ -1768,9 +1786,11 @@ @unittest.skipUnless(PY34, 'need python 3.4 or later') def test_log_destroyed_pending_task(self): + Task = self.__class__.Task + @asyncio.coroutine def kill_me(loop): - future = asyncio.Future(loop=loop) + future = self.new_future(loop) yield from future # at this point, the only reference to kill_me() task is # the Task._wakeup() method in future._callbacks @@ -1783,7 +1803,7 @@ # schedule the task coro = kill_me(self.loop) task = asyncio.ensure_future(coro, loop=self.loop) - self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), {task}) + self.assertEqual(Task.all_tasks(loop=self.loop), {task}) # execute the task so it waits for future self.loop._run_once() @@ -1798,7 +1818,7 @@ # no more reference to kill_me() task: the task is destroyed by the GC support.gc_collect() - self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), set()) + self.assertEqual(Task.all_tasks(loop=self.loop), set()) mock_handler.assert_called_with(self.loop, { 'message': 'Task was destroyed but it is pending!', @@ -1863,10 +1883,10 @@ def test_task_source_traceback(self): self.loop.set_debug(True) - task = asyncio.Task(coroutine_function(), loop=self.loop) + task = self.new_task(self.loop, coroutine_function()) lineno = sys._getframe().f_lineno - 1 self.assertIsInstance(task._source_traceback, list) - self.assertEqual(task._source_traceback[-1][:3], + self.assertEqual(task._source_traceback[-2][:3], (__file__, lineno, 'test_task_source_traceback')) @@ -1878,7 +1898,7 @@ @asyncio.coroutine def blocking_coroutine(): - fut = asyncio.Future(loop=loop) + fut = self.new_future(loop) # Block: fut result is never set yield from fut @@ -1905,7 +1925,7 @@ loop = asyncio.new_event_loop() self.addCleanup(loop.close) - fut = asyncio.Future(loop=loop) + fut = self.new_future(loop) # The indirection fut->child_coro is needed since otherwise the # gathering task is done at the same time as the child future def child_coro(): @@ -1929,6 +1949,157 @@ self.assertFalse(gather_task.cancelled()) self.assertEqual(gather_task.result(), [42]) + @mock.patch('asyncio.base_events.logger') + def test_error_in_call_soon(self, m_log): + def call_soon(callback, *args): + raise ValueError + self.loop.call_soon = call_soon + + @asyncio.coroutine + def coro(): + pass + + self.assertFalse(m_log.error.called) + + with self.assertRaises(ValueError): + self.new_task(self.loop, coro()) + + self.assertTrue(m_log.error.called) + message = m_log.error.call_args[0][0] + self.assertIn('Task was destroyed but it is pending', message) + + self.assertEqual(self.Task.all_tasks(self.loop), set()) + + +def add_subclass_tests(cls): + BaseTask = cls.Task + BaseFuture = cls.Future + + if BaseTask is None or BaseFuture is None: + return cls + + class CommonFuture: + def __init__(self, *args, **kwargs): + self.calls = collections.defaultdict(lambda: 0) + super().__init__(*args, **kwargs) + + def _schedule_callbacks(self): + self.calls['_schedule_callbacks'] += 1 + return super()._schedule_callbacks() + + def add_done_callback(self, *args): + self.calls['add_done_callback'] += 1 + return super().add_done_callback(*args) + + class Task(CommonFuture, BaseTask): + def _step(self, *args): + self.calls['_step'] += 1 + return super()._step(*args) + + def _wakeup(self, *args): + self.calls['_wakeup'] += 1 + return super()._wakeup(*args) + + class Future(CommonFuture, BaseFuture): + pass + + def test_subclasses_ctask_cfuture(self): + fut = self.Future(loop=self.loop) + + async def func(): + self.loop.call_soon(lambda: fut.set_result('spam')) + return await fut + + task = self.Task(func(), loop=self.loop) + + result = self.loop.run_until_complete(task) + + self.assertEqual(result, 'spam') + + self.assertEqual( + dict(task.calls), + {'_step': 2, '_wakeup': 1, 'add_done_callback': 1, + '_schedule_callbacks': 1}) + + self.assertEqual( + dict(fut.calls), + {'add_done_callback': 1, '_schedule_callbacks': 1}) + + # Add patched Task & Future back to the test case + cls.Task = Task + cls.Future = Future + + # Add an extra unit-test + cls.test_subclasses_ctask_cfuture = test_subclasses_ctask_cfuture + + # Disable the "test_task_source_traceback" test + # (the test is hardcoded for a particular call stack, which + # is slightly different for Task subclasses) + cls.test_task_source_traceback = None + + return cls + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CTask_CFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + Future = getattr(futures, '_CFuture', None) + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') + at add_subclass_tests +class CTask_CFuture_SubclassTests(BaseTaskTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + Future = getattr(futures, '_CFuture', None) + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CTask_PyFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + Future = futures._PyFuture + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class PyTask_CFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = tasks._PyTask + Future = getattr(futures, '_CFuture', None) + + +class PyTask_PyFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = tasks._PyTask + Future = futures._PyFuture + + + at add_subclass_tests +class PyTask_PyFuture_SubclassTests(BaseTaskTests, test_utils.TestCase): + Task = tasks._PyTask + Future = futures._PyFuture + + +class GenericTaskTests(test_utils.TestCase): + + def test_future_subclass(self): + self.assertTrue(issubclass(asyncio.Task, asyncio.Future)) + + def test_asyncio_module_compiled(self): + # Because of circular imports it's easy to make _asyncio + # module non-importable. This is a simple test that will + # fail on systems where C modules were successfully compiled + # (hence the test for _functools), but _asyncio somehow didn't. + try: + import _functools + except ImportError: + pass + else: + try: + import _asyncio + except ImportError: + self.fail('_asyncio module is missing') + class GatherTestsBase: diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2,20 +2,35 @@ #include "structmember.h" +/*[clinic input] +module _asyncio +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8fd17862aa989c69]*/ + + /* identifiers used from some functions */ +_Py_IDENTIFIER(add_done_callback); _Py_IDENTIFIER(call_soon); +_Py_IDENTIFIER(cancel); +_Py_IDENTIFIER(send); +_Py_IDENTIFIER(throw); +_Py_IDENTIFIER(_step); +_Py_IDENTIFIER(_schedule_callbacks); +_Py_IDENTIFIER(_wakeup); /* State of the _asyncio module */ +static PyObject *all_tasks; +static PyDictObject *current_tasks; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; -static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_future_repr_info_func; +static PyObject *asyncio_task_repr_info_func; +static PyObject *asyncio_task_get_stack_func; +static PyObject *asyncio_task_print_stack_func; static PyObject *asyncio_InvalidStateError; static PyObject *asyncio_CancelledError; - - -/* Get FutureIter from Future */ -static PyObject* new_future_iter(PyObject *fut); +static PyObject *inspect_isgenerator; typedef enum { @@ -24,24 +39,57 @@ STATE_FINISHED } fut_state; +#define FutureObj_HEAD(prefix) \ + PyObject_HEAD \ + PyObject *prefix##_loop; \ + PyObject *prefix##_callbacks; \ + PyObject *prefix##_exception; \ + PyObject *prefix##_result; \ + PyObject *prefix##_source_tb; \ + fut_state prefix##_state; \ + int prefix##_log_tb; \ + int prefix##_blocking; \ + PyObject *dict; \ + PyObject *prefix##_weakreflist; + +typedef struct { + FutureObj_HEAD(fut) +} FutureObj; + +typedef struct { + FutureObj_HEAD(task) + PyObject *task_fut_waiter; + PyObject *task_coro; + int task_must_cancel; + int task_log_destroy_pending; +} TaskObj; typedef struct { PyObject_HEAD - PyObject *fut_loop; - PyObject *fut_callbacks; - PyObject *fut_exception; - PyObject *fut_result; - PyObject *fut_source_tb; - fut_state fut_state; - int fut_log_tb; - int fut_blocking; - PyObject *dict; - PyObject *fut_weakreflist; -} FutureObj; + TaskObj *sw_task; + PyObject *sw_arg; +} TaskSendMethWrapper; +typedef struct { + PyObject_HEAD + TaskObj *ww_task; +} TaskWakeupMethWrapper; + + +#include "clinic/_asynciomodule.c.h" + + +/*[clinic input] +class _asyncio.Future "FutureObj *" "&Future_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=00d3e4abca711e0f]*/ + +/* Get FutureIter from Future */ +static PyObject* future_new_iter(PyObject *); +static inline int future_call_schedule_callbacks(FutureObj *); static int -_schedule_callbacks(FutureObj *fut) +future_schedule_callbacks(FutureObj *fut) { Py_ssize_t len; PyObject* iters; @@ -87,16 +135,11 @@ } static int -FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +future_init(FutureObj *fut, PyObject *loop) { - static char *kwlist[] = {"loop", NULL}; - PyObject *loop = NULL; PyObject *res = NULL; _Py_IDENTIFIER(get_debug); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { - return -1; - } if (loop == NULL || loop == Py_None) { loop = PyObject_CallObject(asyncio_get_event_loop, NULL); if (loop == NULL) { @@ -128,106 +171,12 @@ if (fut->fut_callbacks == NULL) { return -1; } + return 0; } -static int -FutureObj_clear(FutureObj *fut) -{ - Py_CLEAR(fut->fut_loop); - Py_CLEAR(fut->fut_callbacks); - Py_CLEAR(fut->fut_result); - Py_CLEAR(fut->fut_exception); - Py_CLEAR(fut->fut_source_tb); - Py_CLEAR(fut->dict); - return 0; -} - -static int -FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) -{ - Py_VISIT(fut->fut_loop); - Py_VISIT(fut->fut_callbacks); - Py_VISIT(fut->fut_result); - Py_VISIT(fut->fut_exception); - Py_VISIT(fut->fut_source_tb); - Py_VISIT(fut->dict); - return 0; -} - -PyDoc_STRVAR(pydoc_result, - "Return the result this future represents.\n" - "\n" - "If the future has been cancelled, raises CancelledError. If the\n" - "future's result isn't yet available, raises InvalidStateError. If\n" - "the future is done and has an exception set, this exception is raised." -); - static PyObject * -FutureObj_result(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - fut->fut_log_tb = 0; - if (fut->fut_exception != NULL) { - PyObject *type = NULL; - type = PyExceptionInstance_Class(fut->fut_exception); - PyErr_SetObject(type, fut->fut_exception); - return NULL; - } - - Py_INCREF(fut->fut_result); - return fut->fut_result; -} - -PyDoc_STRVAR(pydoc_exception, - "Return the exception that was set on this future.\n" - "\n" - "The exception (or None if no exception was set) is returned only if\n" - "the future is done. If the future has been cancelled, raises\n" - "CancelledError. If the future isn't done yet, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_exception(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - if (fut->fut_exception != NULL) { - fut->fut_log_tb = 0; - Py_INCREF(fut->fut_exception); - return fut->fut_exception; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_set_result, - "Mark the future done and set its result.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_set_result(FutureObj *fut, PyObject *res) +future_set_result(FutureObj *fut, PyObject *res) { if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); @@ -238,21 +187,14 @@ fut->fut_result = res; fut->fut_state = STATE_FINISHED; - if (_schedule_callbacks(fut) == -1) { + if (future_call_schedule_callbacks(fut) == -1) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(pydoc_set_exception, - "Mark the future done and set an exception.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - static PyObject * -FutureObj_set_exception(FutureObj *fut, PyObject *exc) +future_set_exception(FutureObj *fut, PyObject *exc) { PyObject *exc_val = NULL; @@ -287,7 +229,7 @@ fut->fut_exception = exc_val; fut->fut_state = STATE_FINISHED; - if (_schedule_callbacks(fut) == -1) { + if (future_call_schedule_callbacks(fut) == -1) { return NULL; } @@ -295,16 +237,50 @@ Py_RETURN_NONE; } -PyDoc_STRVAR(pydoc_add_done_callback, - "Add a callback to be run when the future becomes done.\n" - "\n" - "The callback is called with a single argument - the future object. If\n" - "the future is already done when this is called, the callback is\n" - "scheduled with call_soon."; -); +static int +future_get_result(FutureObj *fut, PyObject **result) +{ + PyObject *exc; + + if (fut->fut_state == STATE_CANCELLED) { + exc = _PyObject_CallNoArg(asyncio_CancelledError); + if (exc == NULL) { + return -1; + } + *result = exc; + return 1; + } + + if (fut->fut_state != STATE_FINISHED) { + PyObject *msg = PyUnicode_FromString("Result is not ready."); + if (msg == NULL) { + return -1; + } + + exc = _PyObject_CallArg1(asyncio_InvalidStateError, msg); + Py_DECREF(msg); + if (exc == NULL) { + return -1; + } + + *result = exc; + return 1; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + Py_INCREF(fut->fut_exception); + *result = fut->fut_exception; + return 1; + } + + Py_INCREF(fut->fut_result); + *result = fut->fut_result; + return 0; +} static PyObject * -FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +future_add_done_callback(FutureObj *fut, PyObject *arg) { if (fut->fut_state != STATE_PENDING) { PyObject *handle = _PyObject_CallMethodId( @@ -326,19 +302,216 @@ Py_RETURN_NONE; } -PyDoc_STRVAR(pydoc_remove_done_callback, - "Remove all instances of a callback from the \"call when done\" list.\n" - "\n" - "Returns the number of callbacks removed." -); +static PyObject * +future_cancel(FutureObj *fut) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (future_call_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +/*[clinic input] +_asyncio.Future.__init__ + + * + loop: 'O' = NULL + +This class is *almost* compatible with concurrent.futures.Future. + + Differences: + + - result() and exception() do not take a timeout argument and + raise an exception when the future isn't done yet. + + - Callbacks registered with add_done_callback() are always called + via the event loop's call_soon_threadsafe(). + + - This class is not compatible with the wait() and as_completed() + methods in the concurrent.futures package. +[clinic start generated code]*/ + +static int +_asyncio_Future___init___impl(FutureObj *self, PyObject *loop) +/*[clinic end generated code: output=9ed75799eaccb5d6 input=8e1681f23605be2d]*/ + +{ + return future_init(self, loop); +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +/*[clinic input] +_asyncio.Future.result + +Return the result this future represents. + +If the future has been cancelled, raises CancelledError. If the +future's result isn't yet available, raises InvalidStateError. If +the future is done and has an exception set, this exception is raised. +[clinic start generated code]*/ static PyObject * -FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +_asyncio_Future_result_impl(FutureObj *self) +/*[clinic end generated code: output=f35f940936a4b1e5 input=49ecf9cf5ec50dc5]*/ +{ + PyObject *result; + int res = future_get_result(self, &result); + + if (res == -1) { + return NULL; + } + + if (res == 0) { + return result; + } + + assert(res == 1); + + PyErr_SetObject(PyExceptionInstance_Class(result), result); + Py_DECREF(result); + return NULL; +} + +/*[clinic input] +_asyncio.Future.exception + +Return the exception that was set on this future. + +The exception (or None if no exception was set) is returned only if +the future is done. If the future has been cancelled, raises +CancelledError. If the future isn't done yet, raises +InvalidStateError. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_exception_impl(FutureObj *self) +/*[clinic end generated code: output=88b20d4f855e0710 input=733547a70c841c68]*/ +{ + if (self->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (self->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (self->fut_exception != NULL) { + self->fut_log_tb = 0; + Py_INCREF(self->fut_exception); + return self->fut_exception; + } + + Py_RETURN_NONE; +} + +/*[clinic input] +_asyncio.Future.set_result + + res: 'O' + / + +Mark the future done and set its result. + +If the future is already done when this method is called, raises +InvalidStateError. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_set_result(FutureObj *self, PyObject *res) +/*[clinic end generated code: output=a620abfc2796bfb6 input=8619565e0503357e]*/ +{ + return future_set_result(self, res); +} + +/*[clinic input] +_asyncio.Future.set_exception + + exception: 'O' + / + +Mark the future done and set an exception. + +If the future is already done when this method is called, raises +InvalidStateError. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_set_exception(FutureObj *self, PyObject *exception) +/*[clinic end generated code: output=f1c1b0cd321be360 input=1377dbe15e6ea186]*/ +{ + return future_set_exception(self, exception); +} + +/*[clinic input] +_asyncio.Future.add_done_callback + + fn: 'O' + / + +Add a callback to be run when the future becomes done. + +The callback is called with a single argument - the future object. If +the future is already done when this is called, the callback is +scheduled with call_soon. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_add_done_callback(FutureObj *self, PyObject *fn) +/*[clinic end generated code: output=819e09629b2ec2b5 input=8cce187e32cec6a8]*/ +{ + return future_add_done_callback(self, fn); +} + +/*[clinic input] +_asyncio.Future.remove_done_callback + + fn: 'O' + / + +Remove all instances of a callback from the "call when done" list. + +Returns the number of callbacks removed. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn) +/*[clinic end generated code: output=5ab1fb52b24ef31f input=3fedb73e1409c31c]*/ { PyObject *newlist; Py_ssize_t len, i, j=0; - len = PyList_GET_SIZE(fut->fut_callbacks); + len = PyList_GET_SIZE(self->fut_callbacks); if (len == 0) { return PyLong_FromSsize_t(0); } @@ -350,9 +523,9 @@ for (i = 0; i < len; i++) { int ret; - PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i); - if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + if ((ret = PyObject_RichCompareBool(fn, item, Py_EQ)) < 0) { goto fail; } if (ret == 0) { @@ -365,7 +538,7 @@ if (PyList_SetSlice(newlist, j, len, NULL) < 0) { goto fail; } - if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) { goto fail; } Py_DECREF(newlist); @@ -376,35 +549,34 @@ return NULL; } -PyDoc_STRVAR(pydoc_cancel, - "Cancel the future and schedule callbacks.\n" - "\n" - "If the future is already done or cancelled, return False. Otherwise,\n" - "change the future's state to cancelled, schedule the callbacks and\n" - "return True." -); +/*[clinic input] +_asyncio.Future.cancel + +Cancel the future and schedule callbacks. + +If the future is already done or cancelled, return False. Otherwise, +change the future's state to cancelled, schedule the callbacks and +return True. +[clinic start generated code]*/ static PyObject * -FutureObj_cancel(FutureObj *fut, PyObject *arg) +_asyncio_Future_cancel_impl(FutureObj *self) +/*[clinic end generated code: output=e45b932ba8bd68a1 input=515709a127995109]*/ { - if (fut->fut_state != STATE_PENDING) { - Py_RETURN_FALSE; - } - fut->fut_state = STATE_CANCELLED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - - Py_RETURN_TRUE; + return future_cancel(self); } -PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); +/*[clinic input] +_asyncio.Future.cancelled + +Return True if the future was cancelled. +[clinic start generated code]*/ static PyObject * -FutureObj_cancelled(FutureObj *fut, PyObject *arg) +_asyncio_Future_cancelled_impl(FutureObj *self) +/*[clinic end generated code: output=145197ced586357d input=943ab8b7b7b17e45]*/ { - if (fut->fut_state == STATE_CANCELLED) { + if (self->fut_state == STATE_CANCELLED) { Py_RETURN_TRUE; } else { @@ -412,17 +584,20 @@ } } -PyDoc_STRVAR(pydoc_done, - "Return True if the future is done.\n" - "\n" - "Done means either that a result / exception are available, or that the\n" - "future was cancelled." -); +/*[clinic input] +_asyncio.Future.done + +Return True if the future is done. + +Done means either that a result / exception are available, or that the +future was cancelled. +[clinic start generated code]*/ static PyObject * -FutureObj_done(FutureObj *fut, PyObject *arg) +_asyncio_Future_done_impl(FutureObj *self) +/*[clinic end generated code: output=244c5ac351145096 input=28d7b23fdb65d2ac]*/ { - if (fut->fut_state == STATE_PENDING) { + if (self->fut_state == STATE_PENDING) { Py_RETURN_FALSE; } else { @@ -538,13 +713,31 @@ return ret; } -static PyObject* -FutureObj__repr_info(FutureObj *fut) +/*[clinic input] +_asyncio.Future._repr_info +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future__repr_info_impl(FutureObj *self) +/*[clinic end generated code: output=fa69e901bd176cfb input=f21504d8e2ae1ca2]*/ { - if (asyncio_repr_info_func == NULL) { - return PyList_New(0); + return PyObject_CallFunctionObjArgs( + asyncio_future_repr_info_func, self, NULL); +} + +/*[clinic input] +_asyncio.Future._schedule_callbacks +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future__schedule_callbacks_impl(FutureObj *self) +/*[clinic end generated code: output=5e8958d89ea1c5dc input=4f5f295f263f4a88]*/ +{ + int ret = future_schedule_callbacks(self); + if (ret == -1) { + return NULL; } - return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); + Py_RETURN_NONE; } static PyObject * @@ -661,43 +854,39 @@ static PyAsyncMethods FutureType_as_async = { - (unaryfunc)new_future_iter, /* am_await */ + (unaryfunc)future_new_iter, /* am_await */ 0, /* am_aiter */ 0 /* am_anext */ }; static PyMethodDef FutureType_methods[] = { - {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, - {"add_done_callback", - (PyCFunction)FutureObj_add_done_callback, - METH_O, pydoc_add_done_callback}, - {"remove_done_callback", - (PyCFunction)FutureObj_remove_done_callback, - METH_O, pydoc_remove_done_callback}, - {"set_result", - (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, - {"set_exception", - (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, - {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, - {"cancelled", - (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, - {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, - {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, - {"exception", - (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + _ASYNCIO_FUTURE_RESULT_METHODDEF + _ASYNCIO_FUTURE_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_SET_RESULT_METHODDEF + _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_CANCEL_METHODDEF + _ASYNCIO_FUTURE_CANCELLED_METHODDEF + _ASYNCIO_FUTURE_DONE_METHODDEF + _ASYNCIO_FUTURE__REPR_INFO_METHODDEF + _ASYNCIO_FUTURE__SCHEDULE_CALLBACKS_METHODDEF {NULL, NULL} /* Sentinel */ }; +#define FUTURE_COMMON_GETSETLIST \ + {"_state", (getter)FutureObj_get_state, NULL, NULL}, \ + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \ + (setter)FutureObj_set_blocking, NULL}, \ + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, \ + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \ + {"_result", (getter)FutureObj_get_result, NULL, NULL}, \ + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \ + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, \ + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + static PyGetSetDef FutureType_getsetlist[] = { - {"_state", (getter)FutureObj_get_state, NULL, NULL}, - {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, - (setter)FutureObj_set_blocking, NULL}, - {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, - {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, - {"_result", (getter)FutureObj_get_result, NULL, NULL}, - {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, - {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, - {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + FUTURE_COMMON_GETSETLIST {NULL} /* Sentinel */ }; @@ -712,25 +901,46 @@ .tp_repr = (reprfunc)FutureObj_repr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, - .tp_doc = "Fast asyncio.Future implementation.", + .tp_doc = _asyncio_Future___init____doc__, .tp_traverse = (traverseproc)FutureObj_traverse, .tp_clear = (inquiry)FutureObj_clear, .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), - .tp_iter = (getiterfunc)new_future_iter, + .tp_iter = (getiterfunc)future_new_iter, .tp_methods = FutureType_methods, .tp_getset = FutureType_getsetlist, .tp_dictoffset = offsetof(FutureObj, dict), - .tp_init = (initproc)FutureObj_init, + .tp_init = (initproc)_asyncio_Future___init__, .tp_new = PyType_GenericNew, .tp_finalize = (destructor)FutureObj_finalize, }; +#define Future_CheckExact(obj) (Py_TYPE(obj) == &FutureType) + +static inline int +future_call_schedule_callbacks(FutureObj *fut) +{ + if (Future_CheckExact(fut)) { + return future_schedule_callbacks(fut); + } + else { + /* `fut` is a subclass of Future */ + PyObject *ret = _PyObject_CallMethodId( + (PyObject*)fut, &PyId__schedule_callbacks, NULL); + if (ret == NULL) { + return -1; + } + + Py_DECREF(ret); + return 0; + } +} + static void FutureObj_dealloc(PyObject *self) { FutureObj *fut = (FutureObj *)self; - if (Py_TYPE(fut) == &FutureType) { + if (Future_CheckExact(fut)) { /* When fut is subclass of Future, finalizer is called from * subtype_dealloc. */ @@ -744,7 +954,7 @@ PyObject_ClearWeakRefs(self); } - FutureObj_clear(fut); + (void)FutureObj_clear(fut); Py_TYPE(fut)->tp_free(fut); } @@ -759,7 +969,7 @@ static void FutureIter_dealloc(futureiterobject *it) { - _PyObject_GC_UNTRACK(it); + PyObject_GC_UnTrack(it); Py_XDECREF(it->future); PyObject_GC_Del(it); } @@ -785,7 +995,7 @@ return NULL; } - res = FutureObj_result(fut, NULL); + res = _asyncio_Future_result_impl(fut); if (res != NULL) { /* The result of the Future is not an exception. @@ -884,37 +1094,19 @@ static PyTypeObject FutureIterType = { PyVarObject_HEAD_INIT(0, 0) "_asyncio.FutureIter", - sizeof(futureiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)FutureIter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 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 */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)FutureIter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)FutureIter_iternext, /* tp_iternext */ - FutureIter_methods, /* tp_methods */ - 0, /* tp_members */ + .tp_basicsize = sizeof(futureiterobject), + .tp_itemsize = 0, + .tp_dealloc = (destructor)FutureIter_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)FutureIter_traverse, + .tp_iter = PyObject_SelfIter, + .tp_iternext = (iternextfunc)FutureIter_iternext, + .tp_methods = FutureIter_methods, }; static PyObject * -new_future_iter(PyObject *fut) +future_new_iter(PyObject *fut) { futureiterobject *it; @@ -932,69 +1124,1284 @@ return (PyObject*)it; } -/*********************** Module **************************/ + +/*********************** Task **************************/ + + +/*[clinic input] +class _asyncio.Task "TaskObj *" "&Task_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=719dcef0fcc03b37]*/ + +static int task_call_step_soon(TaskObj *, PyObject *); +static inline PyObject * task_call_wakeup(TaskObj *, PyObject *); +static inline PyObject * task_call_step(TaskObj *, PyObject *); +static PyObject * task_wakeup(TaskObj *, PyObject *); +static PyObject * task_step(TaskObj *, PyObject *); + +/* ----- Task._step wrapper */ static int -init_module(void) +TaskSendMethWrapper_clear(TaskSendMethWrapper *o) { - PyObject *module = NULL; + Py_CLEAR(o->sw_task); + Py_CLEAR(o->sw_arg); + return 0; +} - module = PyImport_ImportModule("traceback"); - if (module == NULL) { +static void +TaskSendMethWrapper_dealloc(TaskSendMethWrapper *o) +{ + PyObject_GC_UnTrack(o); + (void)TaskSendMethWrapper_clear(o); + Py_TYPE(o)->tp_free(o); +} + +static PyObject * +TaskSendMethWrapper_call(TaskSendMethWrapper *o, + PyObject *args, PyObject *kwds) +{ + return task_call_step(o->sw_task, o->sw_arg); +} + +static int +TaskSendMethWrapper_traverse(TaskSendMethWrapper *o, + visitproc visit, void *arg) +{ + Py_VISIT(o->sw_task); + Py_VISIT(o->sw_arg); + return 0; +} + +static PyObject * +TaskSendMethWrapper_get___self__(TaskSendMethWrapper *o) +{ + if (o->sw_task) { + Py_INCREF(o->sw_task); + return (PyObject*)o->sw_task; + } + Py_RETURN_NONE; +} + +static PyGetSetDef TaskSendMethWrapper_getsetlist[] = { + {"__self__", (getter)TaskSendMethWrapper_get___self__, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +PyTypeObject TaskSendMethWrapper_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "TaskSendMethWrapper", + .tp_basicsize = sizeof(TaskSendMethWrapper), + .tp_itemsize = 0, + .tp_getset = TaskSendMethWrapper_getsetlist, + .tp_dealloc = (destructor)TaskSendMethWrapper_dealloc, + .tp_call = (ternaryfunc)TaskSendMethWrapper_call, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)TaskSendMethWrapper_traverse, + .tp_clear = (inquiry)TaskSendMethWrapper_clear, +}; + +static PyObject * +TaskSendMethWrapper_new(TaskObj *task, PyObject *arg) +{ + TaskSendMethWrapper *o; + o = PyObject_GC_New(TaskSendMethWrapper, &TaskSendMethWrapper_Type); + if (o == NULL) { + return NULL; + } + + Py_INCREF(task); + o->sw_task = task; + + Py_XINCREF(arg); + o->sw_arg = arg; + + PyObject_GC_Track(o); + return (PyObject*) o; +} + +/* ----- Task._wakeup wrapper */ + +static PyObject * +TaskWakeupMethWrapper_call(TaskWakeupMethWrapper *o, + PyObject *args, PyObject *kwds) +{ + PyObject *fut; + + if (!PyArg_ParseTuple(args, "O|", &fut)) { + return NULL; + } + + return task_call_wakeup(o->ww_task, fut); +} + +static int +TaskWakeupMethWrapper_clear(TaskWakeupMethWrapper *o) +{ + Py_CLEAR(o->ww_task); + return 0; +} + +static int +TaskWakeupMethWrapper_traverse(TaskWakeupMethWrapper *o, + visitproc visit, void *arg) +{ + Py_VISIT(o->ww_task); + return 0; +} + +static void +TaskWakeupMethWrapper_dealloc(TaskWakeupMethWrapper *o) +{ + PyObject_GC_UnTrack(o); + (void)TaskWakeupMethWrapper_clear(o); + Py_TYPE(o)->tp_free(o); +} + +PyTypeObject TaskWakeupMethWrapper_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "TaskWakeupMethWrapper", + .tp_basicsize = sizeof(TaskWakeupMethWrapper), + .tp_itemsize = 0, + .tp_dealloc = (destructor)TaskWakeupMethWrapper_dealloc, + .tp_call = (ternaryfunc)TaskWakeupMethWrapper_call, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)TaskWakeupMethWrapper_traverse, + .tp_clear = (inquiry)TaskWakeupMethWrapper_clear, +}; + +static PyObject * +TaskWakeupMethWrapper_new(TaskObj *task) +{ + TaskWakeupMethWrapper *o; + o = PyObject_GC_New(TaskWakeupMethWrapper, &TaskWakeupMethWrapper_Type); + if (o == NULL) { + return NULL; + } + + Py_INCREF(task); + o->ww_task = task; + + PyObject_GC_Track(o); + return (PyObject*) o; +} + +/* ----- Task */ + +/*[clinic input] +_asyncio.Task.__init__ + + coro: 'O' + * + loop: 'O' = NULL + +A coroutine wrapped in a Future. +[clinic start generated code]*/ + +static int +_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop) +/*[clinic end generated code: output=9f24774c2287fc2f input=71d8d28c201a18cd]*/ +{ + PyObject *res; + _Py_IDENTIFIER(add); + + if (future_init((FutureObj*)self, loop)) { return -1; } - // new reference - traceback_extract_stack = PyObject_GetAttrString(module, "extract_stack"); - if (traceback_extract_stack == NULL) { - goto fail; + + self->task_fut_waiter = NULL; + self->task_must_cancel = 0; + self->task_log_destroy_pending = 1; + + Py_INCREF(coro); + self->task_coro = coro; + + if (task_call_step_soon(self, NULL)) { + return -1; } - Py_DECREF(module); - module = PyImport_ImportModule("asyncio.events"); - if (module == NULL) { - goto fail; + res = _PyObject_CallMethodId(all_tasks, &PyId_add, "O", self, NULL); + if (res == NULL) { + return -1; } - asyncio_get_event_loop = PyObject_GetAttrString(module, "get_event_loop"); - if (asyncio_get_event_loop == NULL) { - goto fail; + Py_DECREF(res); + + return 0; +} + +static int +TaskObj_clear(TaskObj *task) +{ + (void)FutureObj_clear((FutureObj*) task); + Py_CLEAR(task->task_coro); + Py_CLEAR(task->task_fut_waiter); + return 0; +} + +static int +TaskObj_traverse(TaskObj *task, visitproc visit, void *arg) +{ + Py_VISIT(task->task_coro); + Py_VISIT(task->task_fut_waiter); + (void)FutureObj_traverse((FutureObj*) task, visit, arg); + return 0; +} + +static PyObject * +TaskObj_get_log_destroy_pending(TaskObj *task) +{ + if (task->task_log_destroy_pending) { + Py_RETURN_TRUE; } - Py_DECREF(module); + else { + Py_RETURN_FALSE; + } +} - module = PyImport_ImportModule("asyncio.futures"); - if (module == NULL) { - goto fail; +static int +TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; } - asyncio_repr_info_func = PyObject_GetAttrString(module, - "_future_repr_info"); - if (asyncio_repr_info_func == NULL) { + task->task_log_destroy_pending = is_true; + return 0; +} + +static PyObject * +TaskObj_get_must_cancel(TaskObj *task) +{ + if (task->task_must_cancel) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +TaskObj_get_coro(TaskObj *task) +{ + if (task->task_coro) { + Py_INCREF(task->task_coro); + return task->task_coro; + } + + Py_RETURN_NONE; +} + +static PyObject * +TaskObj_get_fut_waiter(TaskObj *task) +{ + if (task->task_fut_waiter) { + Py_INCREF(task->task_fut_waiter); + return task->task_fut_waiter; + } + + Py_RETURN_NONE; +} + +/*[clinic input] + at classmethod +_asyncio.Task.current_task + + loop: 'O' = NULL + +Return the currently running task in an event loop or None. + +By default the current task for the current event loop is returned. + +None is returned when called not in the context of a Task. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop) +/*[clinic end generated code: output=99fbe7332c516e03 input=cd784537f02cf833]*/ +{ + PyObject *res; + + if (loop == NULL) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return NULL; + } + + res = PyDict_GetItem((PyObject*)current_tasks, loop); + Py_DECREF(loop); + } + else { + res = PyDict_GetItem((PyObject*)current_tasks, loop); + } + + if (res == NULL) { + Py_RETURN_NONE; + } + else { + Py_INCREF(res); + return res; + } +} + +static PyObject * +task_all_tasks(PyObject *loop) +{ + PyObject *task; + PyObject *task_loop; + PyObject *set; + PyObject *iter; + + assert(loop != NULL); + + set = PySet_New(NULL); + if (set == NULL) { + return NULL; + } + + iter = PyObject_GetIter(all_tasks); + if (iter == NULL) { goto fail; } - asyncio_InvalidStateError = PyObject_GetAttrString(module, - "InvalidStateError"); - if (asyncio_InvalidStateError == NULL) { + while ((task = PyIter_Next(iter))) { + task_loop = PyObject_GetAttrString(task, "_loop"); + if (task_loop == NULL) { + Py_DECREF(task); + goto fail; + } + if (task_loop == loop) { + if (PySet_Add(set, task) == -1) { + Py_DECREF(task_loop); + Py_DECREF(task); + goto fail; + } + } + Py_DECREF(task_loop); + Py_DECREF(task); + } + + Py_DECREF(iter); + return set; + +fail: + Py_XDECREF(set); + Py_XDECREF(iter); + return NULL; +} + +/*[clinic input] + at classmethod +_asyncio.Task.all_tasks + + loop: 'O' = NULL + +Return a set of all tasks for an event loop. + +By default all tasks for the current event loop are returned. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop) +/*[clinic end generated code: output=11f9b20749ccca5d input=cd64aa5f88bd5c49]*/ +{ + PyObject *res; + + if (loop == NULL) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return NULL; + } + + res = task_all_tasks(loop); + Py_DECREF(loop); + } + else { + res = task_all_tasks(loop); + } + + return res; +} + +/*[clinic input] +_asyncio.Task._repr_info +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task__repr_info_impl(TaskObj *self) +/*[clinic end generated code: output=6a490eb66d5ba34b input=3c6d051ed3ddec8b]*/ +{ + return PyObject_CallFunctionObjArgs( + asyncio_task_repr_info_func, self, NULL); +} + +/*[clinic input] +_asyncio.Task.cancel + +Request that this task cancel itself. + +This arranges for a CancelledError to be thrown into the +wrapped coroutine on the next cycle through the event loop. +The coroutine then has a chance to clean up or even deny +the request using try/except/finally. + +Unlike Future.cancel, this does not guarantee that the +task will be cancelled: the exception might be caught and +acted upon, delaying cancellation of the task or preventing +cancellation completely. The task may also return a value or +raise a different exception. + +Immediately after this method is called, Task.cancelled() will +not return True (unless the task was already cancelled). A +task will be marked as cancelled when the wrapped coroutine +terminates with a CancelledError exception (even if cancel() +was not called). +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_cancel_impl(TaskObj *self) +/*[clinic end generated code: output=6bfc0479da9d5757 input=13f9bf496695cb52]*/ +{ + if (self->task_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + + if (self->task_fut_waiter) { + PyObject *res; + int is_true; + + res = _PyObject_CallMethodId( + self->task_fut_waiter, &PyId_cancel, NULL); + if (res == NULL) { + return NULL; + } + + is_true = PyObject_IsTrue(res); + Py_DECREF(res); + if (is_true < 0) { + return NULL; + } + + if (is_true) { + Py_RETURN_TRUE; + } + } + + self->task_must_cancel = 1; + Py_RETURN_TRUE; +} + +/*[clinic input] +_asyncio.Task.get_stack + + * + limit: 'O' = None + +Return the list of stack frames for this task's coroutine. + +If the coroutine is not done, this returns the stack where it is +suspended. If the coroutine has completed successfully or was +cancelled, this returns an empty list. If the coroutine was +terminated by an exception, this returns the list of traceback +frames. + +The frames are always ordered from oldest to newest. + +The optional limit gives the maximum number of frames to +return; by default all available frames are returned. Its +meaning differs depending on whether a stack or a traceback is +returned: the newest frames of a stack are returned, but the +oldest frames of a traceback are returned. (This matches the +behavior of the traceback module.) + +For reasons beyond our control, only one stack frame is +returned for a suspended coroutine. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit) +/*[clinic end generated code: output=c9aeeeebd1e18118 input=b1920230a766d17a]*/ +{ + return PyObject_CallFunctionObjArgs( + asyncio_task_get_stack_func, self, limit, NULL); +} + +/*[clinic input] +_asyncio.Task.print_stack + + * + limit: 'O' = None + file: 'O' = None + +Print the stack or traceback for this task's coroutine. + +This produces output similar to that of the traceback module, +for the frames retrieved by get_stack(). The limit argument +is passed to get_stack(). The file argument is an I/O stream +to which the output is written; by default output is written +to sys.stderr. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit, + PyObject *file) +/*[clinic end generated code: output=7339e10314cd3f4d input=19f1e99ab5400bc3]*/ +{ + return PyObject_CallFunctionObjArgs( + asyncio_task_print_stack_func, self, limit, file, NULL); +} + +/*[clinic input] +_asyncio.Task._step + + exc: 'O' = NULL +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task__step_impl(TaskObj *self, PyObject *exc) +/*[clinic end generated code: output=7ed23f0cefd5ae42 input=ada4b2324e5370af]*/ +{ + return task_step(self, exc == Py_None ? NULL : exc); +} + +/*[clinic input] +_asyncio.Task._wakeup + + fut: 'O' +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task__wakeup_impl(TaskObj *self, PyObject *fut) +/*[clinic end generated code: output=75cb341c760fd071 input=11ee4918a5bdbf21]*/ +{ + return task_wakeup(self, fut); +} + +static void +TaskObj_finalize(TaskObj *task) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(task); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(source_traceback); + + PyObject *message = NULL; + PyObject *context = NULL; + PyObject *func = NULL; + PyObject *res = NULL; + + PyObject *error_type, *error_value, *error_traceback; + + if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) { + goto done; + } + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + context = PyDict_New(); + if (context == NULL) { + goto finally; + } + + message = PyUnicode_FromString("Task was destroyed but it is pending!"); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_task, (PyObject*)task) < 0) + { + goto finally; + } + + if (task->task_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + task->task_source_tb) < 0) + { + goto finally; + } + } + + func = _PyObject_GetAttrId(task->task_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + +done: + FutureObj_finalize((FutureObj*)task); +} + +static void TaskObj_dealloc(PyObject *); /* Needs Task_CheckExact */ + +static PyMethodDef TaskType_methods[] = { + _ASYNCIO_FUTURE_RESULT_METHODDEF + _ASYNCIO_FUTURE_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_SET_RESULT_METHODDEF + _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_CANCELLED_METHODDEF + _ASYNCIO_FUTURE_DONE_METHODDEF + _ASYNCIO_TASK_CURRENT_TASK_METHODDEF + _ASYNCIO_TASK_ALL_TASKS_METHODDEF + _ASYNCIO_TASK_CANCEL_METHODDEF + _ASYNCIO_TASK_GET_STACK_METHODDEF + _ASYNCIO_TASK_PRINT_STACK_METHODDEF + _ASYNCIO_TASK__WAKEUP_METHODDEF + _ASYNCIO_TASK__STEP_METHODDEF + _ASYNCIO_TASK__REPR_INFO_METHODDEF + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef TaskType_getsetlist[] = { + FUTURE_COMMON_GETSETLIST + {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending, + (setter)TaskObj_set_log_destroy_pending, NULL}, + {"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL}, + {"_coro", (getter)TaskObj_get_coro, NULL, NULL}, + {"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject TaskType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.Task", + sizeof(TaskObj), /* tp_basicsize */ + .tp_base = &FutureType, + .tp_dealloc = TaskObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = _asyncio_Task___init____doc__, + .tp_traverse = (traverseproc)TaskObj_traverse, + .tp_clear = (inquiry)TaskObj_clear, + .tp_weaklistoffset = offsetof(TaskObj, task_weakreflist), + .tp_iter = (getiterfunc)future_new_iter, + .tp_methods = TaskType_methods, + .tp_getset = TaskType_getsetlist, + .tp_dictoffset = offsetof(TaskObj, dict), + .tp_init = (initproc)_asyncio_Task___init__, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)TaskObj_finalize, +}; + +#define Task_CheckExact(obj) (Py_TYPE(obj) == &TaskType) + +static void +TaskObj_dealloc(PyObject *self) +{ + TaskObj *task = (TaskObj *)self; + + if (Task_CheckExact(self)) { + /* When fut is subclass of Task, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (task->task_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + (void)TaskObj_clear(task); + Py_TYPE(task)->tp_free(task); +} + +static inline PyObject * +task_call_wakeup(TaskObj *task, PyObject *fut) +{ + if (Task_CheckExact(task)) { + return task_wakeup(task, fut); + } + else { + /* `task` is a subclass of Task */ + return _PyObject_CallMethodId( + (PyObject*)task, &PyId__wakeup, "O", fut, NULL); + } +} + +static inline PyObject * +task_call_step(TaskObj *task, PyObject *arg) +{ + if (Task_CheckExact(task)) { + return task_step(task, arg); + } + else { + /* `task` is a subclass of Task */ + if (arg == NULL) { + arg = Py_None; + } + return _PyObject_CallMethodId( + (PyObject*)task, &PyId__step, "O", arg, NULL); + } +} + +static int +task_call_step_soon(TaskObj *task, PyObject *arg) +{ + PyObject *handle; + + PyObject *cb = TaskSendMethWrapper_new(task, arg); + if (cb == NULL) { + return -1; + } + + handle = _PyObject_CallMethodId( + task->task_loop, &PyId_call_soon, "O", cb, NULL); + Py_DECREF(cb); + if (handle == NULL) { + return -1; + } + + Py_DECREF(handle); + return 0; +} + +static PyObject * +task_set_error_soon(TaskObj *task, PyObject *et, const char *format, ...) +{ + PyObject* msg; + + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + msg = PyUnicode_FromFormatV(format, vargs); + va_end(vargs); + + if (msg == NULL) { + return NULL; + } + + PyObject *e = PyObject_CallFunctionObjArgs(et, msg, NULL); + Py_DECREF(msg); + if (e == NULL) { + return NULL; + } + + if (task_call_step_soon(task, e) == -1) { + Py_DECREF(e); + return NULL; + } + + Py_DECREF(e); + Py_RETURN_NONE; +} + +static PyObject * +task_step_impl(TaskObj *task, PyObject *exc) +{ + int res; + int clear_exc = 0; + PyObject *result = NULL; + PyObject *coro = task->task_coro; + PyObject *o; + + if (task->task_state != STATE_PENDING) { + PyErr_Format(PyExc_AssertionError, + "_step(): already done: %R %R", + task, + exc ? exc : Py_None); goto fail; } - asyncio_CancelledError = PyObject_GetAttrString(module, "CancelledError"); - if (asyncio_CancelledError == NULL) { + if (task->task_must_cancel) { + assert(exc != Py_None); + + if (exc) { + /* Check if exc is a CancelledError */ + res = PyObject_IsInstance(exc, asyncio_CancelledError); + if (res == -1) { + /* An error occurred, abort */ + goto fail; + } + if (res == 0) { + /* exc is not CancelledError; reset it to NULL */ + exc = NULL; + } + } + + if (!exc) { + /* exc was not a CancelledError */ + exc = PyObject_CallFunctionObjArgs(asyncio_CancelledError, NULL); + if (!exc) { + goto fail; + } + clear_exc = 1; + } + + task->task_must_cancel = 0; + } + + Py_CLEAR(task->task_fut_waiter); + + if (exc == NULL) { + if (PyGen_CheckExact(coro) || PyCoro_CheckExact(coro)) { + result = _PyGen_Send((PyGenObject*)coro, Py_None); + } + else { + result = _PyObject_CallMethodIdObjArgs( + coro, &PyId_send, Py_None, NULL); + } + } + else { + result = _PyObject_CallMethodIdObjArgs( + coro, &PyId_throw, exc, NULL); + if (clear_exc) { + /* We created 'exc' during this call */ + Py_CLEAR(exc); + } + } + + if (result == NULL) { + PyObject *et, *ev, *tb; + + if (_PyGen_FetchStopIterationValue(&o) == 0) { + /* The error is StopIteration and that means that + the underlying coroutine has resolved */ + PyObject *res = future_set_result((FutureObj*)task, o); + Py_DECREF(o); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + Py_RETURN_NONE; + } + + if (PyErr_ExceptionMatches(asyncio_CancelledError)) { + /* CancelledError */ + PyErr_Clear(); + return future_cancel((FutureObj*)task); + } + + /* Some other exception; pop it and call Task.set_exception() */ + PyErr_Fetch(&et, &ev, &tb); + assert(et); + if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { + PyErr_NormalizeException(&et, &ev, &tb); + } + o = future_set_exception((FutureObj*)task, ev); + if (!o) { + /* An exception in Task.set_exception() */ + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + goto fail; + } + assert(o == Py_None); + Py_CLEAR(o); + + if (!PyErr_GivenExceptionMatches(et, PyExc_Exception)) { + /* We've got a BaseException; re-raise it */ + PyErr_Restore(et, ev, tb); + goto fail; + } + + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + + Py_RETURN_NONE; + } + + if (result == (PyObject*)task) { + /* We have a task that wants to await on itself */ + goto self_await; + } + + /* Check if `result` is FutureObj or TaskObj (and not a subclass) */ + if (Future_CheckExact(result) || Task_CheckExact(result)) { + PyObject *wrapper; + PyObject *res; + FutureObj *fut = (FutureObj*)result; + + /* Check if `result` future is attached to a different loop */ + if (fut->fut_loop != task->task_loop) { + goto different_loop; + } + + if (fut->fut_blocking) { + fut->fut_blocking = 0; + + /* result.add_done_callback(task._wakeup) */ + wrapper = TaskWakeupMethWrapper_new(task); + if (wrapper == NULL) { + goto fail; + } + res = future_add_done_callback((FutureObj*)result, wrapper); + Py_DECREF(wrapper); + if (res == NULL) { + goto fail; + } + Py_DECREF(res); + + /* task._fut_waiter = result */ + task->task_fut_waiter = result; /* no incref is necessary */ + + if (task->task_must_cancel) { + PyObject *r; + r = future_cancel(fut); + if (r == NULL) { + return NULL; + } + if (r == Py_True) { + task->task_must_cancel = 0; + } + Py_DECREF(r); + } + + Py_RETURN_NONE; + } + else { + goto yield_insteadof_yf; + } + } + + /* Check if `result` is a Future-compatible object */ + o = PyObject_GetAttrString(result, "_asyncio_future_blocking"); + if (o == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } + else { + goto fail; + } + } + else { + if (o == Py_None) { + Py_CLEAR(o); + } + else { + /* `result` is a Future-compatible object */ + PyObject *wrapper; + PyObject *res; + + int blocking = PyObject_IsTrue(o); + Py_CLEAR(o); + if (blocking < 0) { + goto fail; + } + + /* Check if `result` future is attached to a different loop */ + PyObject *oloop = PyObject_GetAttrString(result, "_loop"); + if (oloop == NULL) { + goto fail; + } + if (oloop != task->task_loop) { + Py_DECREF(oloop); + goto different_loop; + } + else { + Py_DECREF(oloop); + } + + if (blocking) { + /* result._asyncio_future_blocking = False */ + if (PyObject_SetAttrString( + result, "_asyncio_future_blocking", Py_False) == -1) { + goto fail; + } + + /* result.add_done_callback(task._wakeup) */ + wrapper = TaskWakeupMethWrapper_new(task); + if (wrapper == NULL) { + goto fail; + } + res = _PyObject_CallMethodId( + result, &PyId_add_done_callback, "O", wrapper, NULL); + Py_DECREF(wrapper); + if (res == NULL) { + goto fail; + } + Py_DECREF(res); + + /* task._fut_waiter = result */ + task->task_fut_waiter = result; /* no incref is necessary */ + + if (task->task_must_cancel) { + PyObject *r; + int is_true; + r = _PyObject_CallMethodId(result, &PyId_cancel, NULL); + if (r == NULL) { + return NULL; + } + is_true = PyObject_IsTrue(r); + Py_DECREF(r); + if (is_true < 0) { + return NULL; + } + else if (is_true) { + task->task_must_cancel = 0; + } + } + + Py_RETURN_NONE; + } + else { + goto yield_insteadof_yf; + } + } + } + + /* Check if `result` is None */ + if (result == Py_None) { + /* Bare yield relinquishes control for one event loop iteration. */ + if (task_call_step_soon(task, NULL)) { + goto fail; + } + return result; + } + + /* Check if `result` is a generator */ + o = PyObject_CallFunctionObjArgs(inspect_isgenerator, result, NULL); + if (o == NULL) { + /* An exception in inspect.isgenerator */ + goto fail; + } + res = PyObject_IsTrue(o); + Py_CLEAR(o); + if (res == -1) { + /* An exception while checking if 'val' is True */ + goto fail; + } + if (res == 1) { + /* `result` is a generator */ + PyObject *ret; + ret = task_set_error_soon( + task, PyExc_RuntimeError, + "yield was used instead of yield from for " + "generator in task %R with %S", task, result); + Py_DECREF(result); + return ret; + } + + /* The `result` is none of the above */ + Py_DECREF(result); + return task_set_error_soon( + task, PyExc_RuntimeError, "Task got bad yield: %R", result); + +self_await: + o = task_set_error_soon( + task, PyExc_RuntimeError, + "Task cannot await on itself: %R", task); + Py_DECREF(result); + return o; + +yield_insteadof_yf: + o = task_set_error_soon( + task, PyExc_RuntimeError, + "yield was used instead of yield from " + "in task %R with %R", + task, result); + Py_DECREF(result); + return o; + +different_loop: + o = task_set_error_soon( + task, PyExc_RuntimeError, + "Task %R got Future %R attached to a different loop", + task, result); + Py_DECREF(result); + return o; + +fail: + Py_XDECREF(result); + return NULL; +} + +static PyObject * +task_step(TaskObj *task, PyObject *exc) +{ + PyObject *res; + PyObject *ot; + + if (PyDict_SetItem((PyObject *)current_tasks, + task->task_loop, (PyObject*)task) == -1) + { + return NULL; + } + + res = task_step_impl(task, exc); + + if (res == NULL) { + PyObject *et, *ev, *tb; + PyErr_Fetch(&et, &ev, &tb); + ot = _PyDict_Pop(current_tasks, task->task_loop, NULL); + if (ot == NULL) { + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + return NULL; + } + Py_DECREF(ot); + PyErr_Restore(et, ev, tb); + return NULL; + } + else { + ot = _PyDict_Pop(current_tasks, task->task_loop, NULL); + if (ot == NULL) { + Py_DECREF(res); + return NULL; + } + else { + Py_DECREF(ot); + return res; + } + } +} + +static PyObject * +task_wakeup(TaskObj *task, PyObject *o) +{ + assert(o); + + if (Future_CheckExact(o) || Task_CheckExact(o)) { + PyObject *fut_result = NULL; + int res = future_get_result((FutureObj*)o, &fut_result); + PyObject *result; + + switch(res) { + case -1: + assert(fut_result == NULL); + return NULL; + case 0: + Py_DECREF(fut_result); + return task_call_step(task, NULL); + default: + assert(res == 1); + result = task_call_step(task, fut_result); + Py_DECREF(fut_result); + return result; + } + } + + PyObject *fut_result = PyObject_CallMethod(o, "result", NULL); + if (fut_result == NULL) { + PyObject *et, *ev, *tb; + PyObject *res; + + PyErr_Fetch(&et, &ev, &tb); + if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { + PyErr_NormalizeException(&et, &ev, &tb); + } + + res = task_call_step(task, ev); + + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + + return res; + } + else { + Py_DECREF(fut_result); + return task_call_step(task, NULL); + } +} + + +/*********************** Module **************************/ + + +static void +module_free(void *m) +{ + Py_CLEAR(current_tasks); + Py_CLEAR(all_tasks); + Py_CLEAR(traceback_extract_stack); + Py_CLEAR(asyncio_get_event_loop); + Py_CLEAR(asyncio_future_repr_info_func); + Py_CLEAR(asyncio_task_repr_info_func); + Py_CLEAR(asyncio_task_get_stack_func); + Py_CLEAR(asyncio_task_print_stack_func); + Py_CLEAR(asyncio_InvalidStateError); + Py_CLEAR(asyncio_CancelledError); + Py_CLEAR(inspect_isgenerator); +} + +static int +module_init(void) +{ + PyObject *module = NULL; + PyObject *cls; + +#define WITH_MOD(NAME) \ + Py_CLEAR(module); \ + module = PyImport_ImportModule(NAME); \ + if (module == NULL) { \ + return -1; \ + } + +#define GET_MOD_ATTR(VAR, NAME) \ + VAR = PyObject_GetAttrString(module, NAME); \ + if (VAR == NULL) { \ + goto fail; \ + } + + WITH_MOD("asyncio.events") + GET_MOD_ATTR(asyncio_get_event_loop, "get_event_loop") + + WITH_MOD("asyncio.base_futures") + GET_MOD_ATTR(asyncio_future_repr_info_func, "_future_repr_info") + GET_MOD_ATTR(asyncio_InvalidStateError, "InvalidStateError") + GET_MOD_ATTR(asyncio_CancelledError, "CancelledError") + + WITH_MOD("asyncio.base_tasks") + GET_MOD_ATTR(asyncio_task_repr_info_func, "_task_repr_info") + GET_MOD_ATTR(asyncio_task_get_stack_func, "_task_get_stack") + GET_MOD_ATTR(asyncio_task_print_stack_func, "_task_print_stack") + + WITH_MOD("inspect") + GET_MOD_ATTR(inspect_isgenerator, "isgenerator") + + WITH_MOD("traceback") + GET_MOD_ATTR(traceback_extract_stack, "extract_stack") + + WITH_MOD("weakref") + GET_MOD_ATTR(cls, "WeakSet") + all_tasks = PyObject_CallObject(cls, NULL); + Py_CLEAR(cls); + if (all_tasks == NULL) { goto fail; } - Py_DECREF(module); + current_tasks = (PyDictObject *)PyDict_New(); + if (current_tasks == NULL) { + goto fail; + } + + Py_CLEAR(module); return 0; fail: - Py_CLEAR(traceback_extract_stack); - Py_CLEAR(asyncio_get_event_loop); - Py_CLEAR(asyncio_repr_info_func); - Py_CLEAR(asyncio_InvalidStateError); - Py_CLEAR(asyncio_CancelledError); Py_CLEAR(module); + module_free(NULL); return -1; + +#undef WITH_MOD +#undef GET_MOD_ATTR } - PyDoc_STRVAR(module_doc, "Accelerator module for asyncio"); static struct PyModuleDef _asynciomodule = { @@ -1006,14 +2413,14 @@ NULL, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ - NULL, /* m_free */ + (freefunc)module_free /* m_free */ }; PyMODINIT_FUNC PyInit__asyncio(void) { - if (init_module() < 0) { + if (module_init() < 0) { return NULL; } if (PyType_Ready(&FutureType) < 0) { @@ -1022,6 +2429,15 @@ if (PyType_Ready(&FutureIterType) < 0) { return NULL; } + if (PyType_Ready(&TaskSendMethWrapper_Type) < 0) { + return NULL; + } + if(PyType_Ready(&TaskWakeupMethWrapper_Type) < 0) { + return NULL; + } + if (PyType_Ready(&TaskType) < 0) { + return NULL; + } PyObject *m = PyModule_Create(&_asynciomodule); if (m == NULL) { @@ -1034,5 +2450,11 @@ return NULL; } + Py_INCREF(&TaskType); + if (PyModule_AddObject(m, "Task", (PyObject *)&TaskType) < 0) { + Py_DECREF(&TaskType); + return NULL; + } + return m; } diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/_asynciomodule.c.h @@ -0,0 +1,520 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_asyncio_Future___init____doc__, +"Future(*, loop=None)\n" +"--\n" +"\n" +"This class is *almost* compatible with concurrent.futures.Future.\n" +"\n" +" Differences:\n" +"\n" +" - result() and exception() do not take a timeout argument and\n" +" raise an exception when the future isn\'t done yet.\n" +"\n" +" - Callbacks registered with add_done_callback() are always called\n" +" via the event loop\'s call_soon_threadsafe().\n" +"\n" +" - This class is not compatible with the wait() and as_completed()\n" +" methods in the concurrent.futures package."); + +static int +_asyncio_Future___init___impl(FutureObj *self, PyObject *loop); + +static int +_asyncio_Future___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"loop", NULL}; + static _PyArg_Parser _parser = {"|$O:Future", _keywords, 0}; + PyObject *loop = NULL; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &loop)) { + goto exit; + } + return_value = _asyncio_Future___init___impl((FutureObj *)self, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Future_result__doc__, +"result($self, /)\n" +"--\n" +"\n" +"Return the result this future represents.\n" +"\n" +"If the future has been cancelled, raises CancelledError. If the\n" +"future\'s result isn\'t yet available, raises InvalidStateError. If\n" +"the future is done and has an exception set, this exception is raised."); + +#define _ASYNCIO_FUTURE_RESULT_METHODDEF \ + {"result", (PyCFunction)_asyncio_Future_result, METH_NOARGS, _asyncio_Future_result__doc__}, + +static PyObject * +_asyncio_Future_result_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_result(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_result_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_exception__doc__, +"exception($self, /)\n" +"--\n" +"\n" +"Return the exception that was set on this future.\n" +"\n" +"The exception (or None if no exception was set) is returned only if\n" +"the future is done. If the future has been cancelled, raises\n" +"CancelledError. If the future isn\'t done yet, raises\n" +"InvalidStateError."); + +#define _ASYNCIO_FUTURE_EXCEPTION_METHODDEF \ + {"exception", (PyCFunction)_asyncio_Future_exception, METH_NOARGS, _asyncio_Future_exception__doc__}, + +static PyObject * +_asyncio_Future_exception_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_exception(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_exception_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_set_result__doc__, +"set_result($self, res, /)\n" +"--\n" +"\n" +"Mark the future done and set its result.\n" +"\n" +"If the future is already done when this method is called, raises\n" +"InvalidStateError."); + +#define _ASYNCIO_FUTURE_SET_RESULT_METHODDEF \ + {"set_result", (PyCFunction)_asyncio_Future_set_result, METH_O, _asyncio_Future_set_result__doc__}, + +PyDoc_STRVAR(_asyncio_Future_set_exception__doc__, +"set_exception($self, exception, /)\n" +"--\n" +"\n" +"Mark the future done and set an exception.\n" +"\n" +"If the future is already done when this method is called, raises\n" +"InvalidStateError."); + +#define _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF \ + {"set_exception", (PyCFunction)_asyncio_Future_set_exception, METH_O, _asyncio_Future_set_exception__doc__}, + +PyDoc_STRVAR(_asyncio_Future_add_done_callback__doc__, +"add_done_callback($self, fn, /)\n" +"--\n" +"\n" +"Add a callback to be run when the future becomes done.\n" +"\n" +"The callback is called with a single argument - the future object. If\n" +"the future is already done when this is called, the callback is\n" +"scheduled with call_soon."); + +#define _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF \ + {"add_done_callback", (PyCFunction)_asyncio_Future_add_done_callback, METH_O, _asyncio_Future_add_done_callback__doc__}, + +PyDoc_STRVAR(_asyncio_Future_remove_done_callback__doc__, +"remove_done_callback($self, fn, /)\n" +"--\n" +"\n" +"Remove all instances of a callback from the \"call when done\" list.\n" +"\n" +"Returns the number of callbacks removed."); + +#define _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF \ + {"remove_done_callback", (PyCFunction)_asyncio_Future_remove_done_callback, METH_O, _asyncio_Future_remove_done_callback__doc__}, + +PyDoc_STRVAR(_asyncio_Future_cancel__doc__, +"cancel($self, /)\n" +"--\n" +"\n" +"Cancel the future and schedule callbacks.\n" +"\n" +"If the future is already done or cancelled, return False. Otherwise,\n" +"change the future\'s state to cancelled, schedule the callbacks and\n" +"return True."); + +#define _ASYNCIO_FUTURE_CANCEL_METHODDEF \ + {"cancel", (PyCFunction)_asyncio_Future_cancel, METH_NOARGS, _asyncio_Future_cancel__doc__}, + +static PyObject * +_asyncio_Future_cancel_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_cancel(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_cancel_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_cancelled__doc__, +"cancelled($self, /)\n" +"--\n" +"\n" +"Return True if the future was cancelled."); + +#define _ASYNCIO_FUTURE_CANCELLED_METHODDEF \ + {"cancelled", (PyCFunction)_asyncio_Future_cancelled, METH_NOARGS, _asyncio_Future_cancelled__doc__}, + +static PyObject * +_asyncio_Future_cancelled_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_cancelled(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_cancelled_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_done__doc__, +"done($self, /)\n" +"--\n" +"\n" +"Return True if the future is done.\n" +"\n" +"Done means either that a result / exception are available, or that the\n" +"future was cancelled."); + +#define _ASYNCIO_FUTURE_DONE_METHODDEF \ + {"done", (PyCFunction)_asyncio_Future_done, METH_NOARGS, _asyncio_Future_done__doc__}, + +static PyObject * +_asyncio_Future_done_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_done(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_done_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future__repr_info__doc__, +"_repr_info($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_FUTURE__REPR_INFO_METHODDEF \ + {"_repr_info", (PyCFunction)_asyncio_Future__repr_info, METH_NOARGS, _asyncio_Future__repr_info__doc__}, + +static PyObject * +_asyncio_Future__repr_info_impl(FutureObj *self); + +static PyObject * +_asyncio_Future__repr_info(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future__repr_info_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future__schedule_callbacks__doc__, +"_schedule_callbacks($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_FUTURE__SCHEDULE_CALLBACKS_METHODDEF \ + {"_schedule_callbacks", (PyCFunction)_asyncio_Future__schedule_callbacks, METH_NOARGS, _asyncio_Future__schedule_callbacks__doc__}, + +static PyObject * +_asyncio_Future__schedule_callbacks_impl(FutureObj *self); + +static PyObject * +_asyncio_Future__schedule_callbacks(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future__schedule_callbacks_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task___init____doc__, +"Task(coro, *, loop=None)\n" +"--\n" +"\n" +"A coroutine wrapped in a Future."); + +static int +_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop); + +static int +_asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"coro", "loop", NULL}; + static _PyArg_Parser _parser = {"O|$O:Task", _keywords, 0}; + PyObject *coro; + PyObject *loop = NULL; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &coro, &loop)) { + goto exit; + } + return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task_current_task__doc__, +"current_task($type, /, loop=None)\n" +"--\n" +"\n" +"Return the currently running task in an event loop or None.\n" +"\n" +"By default the current task for the current event loop is returned.\n" +"\n" +"None is returned when called not in the context of a Task."); + +#define _ASYNCIO_TASK_CURRENT_TASK_METHODDEF \ + {"current_task", (PyCFunction)_asyncio_Task_current_task, METH_FASTCALL|METH_CLASS, _asyncio_Task_current_task__doc__}, + +static PyObject * +_asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop); + +static PyObject * +_asyncio_Task_current_task(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"loop", NULL}; + static _PyArg_Parser _parser = {"|O:current_task", _keywords, 0}; + PyObject *loop = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &loop)) { + goto exit; + } + return_value = _asyncio_Task_current_task_impl(type, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task_all_tasks__doc__, +"all_tasks($type, /, loop=None)\n" +"--\n" +"\n" +"Return a set of all tasks for an event loop.\n" +"\n" +"By default all tasks for the current event loop are returned."); + +#define _ASYNCIO_TASK_ALL_TASKS_METHODDEF \ + {"all_tasks", (PyCFunction)_asyncio_Task_all_tasks, METH_FASTCALL|METH_CLASS, _asyncio_Task_all_tasks__doc__}, + +static PyObject * +_asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop); + +static PyObject * +_asyncio_Task_all_tasks(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"loop", NULL}; + static _PyArg_Parser _parser = {"|O:all_tasks", _keywords, 0}; + PyObject *loop = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &loop)) { + goto exit; + } + return_value = _asyncio_Task_all_tasks_impl(type, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task__repr_info__doc__, +"_repr_info($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK__REPR_INFO_METHODDEF \ + {"_repr_info", (PyCFunction)_asyncio_Task__repr_info, METH_NOARGS, _asyncio_Task__repr_info__doc__}, + +static PyObject * +_asyncio_Task__repr_info_impl(TaskObj *self); + +static PyObject * +_asyncio_Task__repr_info(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task__repr_info_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task_cancel__doc__, +"cancel($self, /)\n" +"--\n" +"\n" +"Request that this task cancel itself.\n" +"\n" +"This arranges for a CancelledError to be thrown into the\n" +"wrapped coroutine on the next cycle through the event loop.\n" +"The coroutine then has a chance to clean up or even deny\n" +"the request using try/except/finally.\n" +"\n" +"Unlike Future.cancel, this does not guarantee that the\n" +"task will be cancelled: the exception might be caught and\n" +"acted upon, delaying cancellation of the task or preventing\n" +"cancellation completely. The task may also return a value or\n" +"raise a different exception.\n" +"\n" +"Immediately after this method is called, Task.cancelled() will\n" +"not return True (unless the task was already cancelled). A\n" +"task will be marked as cancelled when the wrapped coroutine\n" +"terminates with a CancelledError exception (even if cancel()\n" +"was not called)."); + +#define _ASYNCIO_TASK_CANCEL_METHODDEF \ + {"cancel", (PyCFunction)_asyncio_Task_cancel, METH_NOARGS, _asyncio_Task_cancel__doc__}, + +static PyObject * +_asyncio_Task_cancel_impl(TaskObj *self); + +static PyObject * +_asyncio_Task_cancel(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task_cancel_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task_get_stack__doc__, +"get_stack($self, /, *, limit=None)\n" +"--\n" +"\n" +"Return the list of stack frames for this task\'s coroutine.\n" +"\n" +"If the coroutine is not done, this returns the stack where it is\n" +"suspended. If the coroutine has completed successfully or was\n" +"cancelled, this returns an empty list. If the coroutine was\n" +"terminated by an exception, this returns the list of traceback\n" +"frames.\n" +"\n" +"The frames are always ordered from oldest to newest.\n" +"\n" +"The optional limit gives the maximum number of frames to\n" +"return; by default all available frames are returned. Its\n" +"meaning differs depending on whether a stack or a traceback is\n" +"returned: the newest frames of a stack are returned, but the\n" +"oldest frames of a traceback are returned. (This matches the\n" +"behavior of the traceback module.)\n" +"\n" +"For reasons beyond our control, only one stack frame is\n" +"returned for a suspended coroutine."); + +#define _ASYNCIO_TASK_GET_STACK_METHODDEF \ + {"get_stack", (PyCFunction)_asyncio_Task_get_stack, METH_FASTCALL, _asyncio_Task_get_stack__doc__}, + +static PyObject * +_asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit); + +static PyObject * +_asyncio_Task_get_stack(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"limit", NULL}; + static _PyArg_Parser _parser = {"|$O:get_stack", _keywords, 0}; + PyObject *limit = Py_None; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &limit)) { + goto exit; + } + return_value = _asyncio_Task_get_stack_impl(self, limit); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task_print_stack__doc__, +"print_stack($self, /, *, limit=None, file=None)\n" +"--\n" +"\n" +"Print the stack or traceback for this task\'s coroutine.\n" +"\n" +"This produces output similar to that of the traceback module,\n" +"for the frames retrieved by get_stack(). The limit argument\n" +"is passed to get_stack(). The file argument is an I/O stream\n" +"to which the output is written; by default output is written\n" +"to sys.stderr."); + +#define _ASYNCIO_TASK_PRINT_STACK_METHODDEF \ + {"print_stack", (PyCFunction)_asyncio_Task_print_stack, METH_FASTCALL, _asyncio_Task_print_stack__doc__}, + +static PyObject * +_asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit, + PyObject *file); + +static PyObject * +_asyncio_Task_print_stack(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"limit", "file", NULL}; + static _PyArg_Parser _parser = {"|$OO:print_stack", _keywords, 0}; + PyObject *limit = Py_None; + PyObject *file = Py_None; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &limit, &file)) { + goto exit; + } + return_value = _asyncio_Task_print_stack_impl(self, limit, file); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task__step__doc__, +"_step($self, /, exc=None)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK__STEP_METHODDEF \ + {"_step", (PyCFunction)_asyncio_Task__step, METH_FASTCALL, _asyncio_Task__step__doc__}, + +static PyObject * +_asyncio_Task__step_impl(TaskObj *self, PyObject *exc); + +static PyObject * +_asyncio_Task__step(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"exc", NULL}; + static _PyArg_Parser _parser = {"|O:_step", _keywords, 0}; + PyObject *exc = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &exc)) { + goto exit; + } + return_value = _asyncio_Task__step_impl(self, exc); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task__wakeup__doc__, +"_wakeup($self, /, fut)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK__WAKEUP_METHODDEF \ + {"_wakeup", (PyCFunction)_asyncio_Task__wakeup, METH_FASTCALL, _asyncio_Task__wakeup__doc__}, + +static PyObject * +_asyncio_Task__wakeup_impl(TaskObj *self, PyObject *fut); + +static PyObject * +_asyncio_Task__wakeup(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"fut", NULL}; + static _PyArg_Parser _parser = {"O:_wakeup", _keywords, 0}; + PyObject *fut; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &fut)) { + goto exit; + } + return_value = _asyncio_Task__wakeup_impl(self, fut); + +exit: + return return_value; +} +/*[clinic end generated code: output=8f036321bb083066 input=a9049054013a1b77]*/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 12:53:34 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 28 Oct 2016 16:53:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTQ0?= =?utf-8?q?=3A_Implement_asyncio=2ETask_in_C=2E?= Message-ID: <20161028165334.32479.62514.E7523DDB@psf.io> https://hg.python.org/cpython/rev/db5ae4f6df8a changeset: 104775:db5ae4f6df8a branch: 3.6 user: Yury Selivanov date: Fri Oct 28 12:52:37 2016 -0400 summary: Issue #28544: Implement asyncio.Task in C. This implementation provides additional 10-20% speed boost for asyncio programs. The patch also fixes _asynciomodule.c to use Arguments Clinic, and makes '_schedule_callbacks' an overridable method (as it was in 3.5). files: Lib/asyncio/base_events.py | 2 +- Lib/asyncio/base_futures.py | 70 + Lib/asyncio/base_tasks.py | 76 + Lib/asyncio/coroutines.py | 4 +- Lib/asyncio/futures.py | 91 +- Lib/asyncio/tasks.py | 80 +- Lib/test/test_asyncio/test_tasks.py | 445 ++- Misc/NEWS | 2 + Modules/_asynciomodule.c | 1984 ++++++++++++-- Modules/clinic/_asynciomodule.c.h | 520 +++ 10 files changed, 2717 insertions(+), 557 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -57,7 +57,7 @@ def _format_handle(handle): cb = handle._callback - if inspect.ismethod(cb) and isinstance(cb.__self__, tasks.Task): + if isinstance(getattr(cb, '__self__', None), tasks.Task): # format the task return repr(cb.__self__) else: diff --git a/Lib/asyncio/base_futures.py b/Lib/asyncio/base_futures.py new file mode 100644 --- /dev/null +++ b/Lib/asyncio/base_futures.py @@ -0,0 +1,70 @@ +__all__ = [] + +import concurrent.futures._base +import reprlib + +from . import events + +Error = concurrent.futures._base.Error +CancelledError = concurrent.futures.CancelledError +TimeoutError = concurrent.futures.TimeoutError + + +class InvalidStateError(Error): + """The operation is not allowed in this state.""" + + +# States for Future. +_PENDING = 'PENDING' +_CANCELLED = 'CANCELLED' +_FINISHED = 'FINISHED' + + +def isfuture(obj): + """Check for a Future. + + This returns True when obj is a Future instance or is advertising + itself as duck-type compatible by setting _asyncio_future_blocking. + See comment in Future for more details. + """ + return getattr(obj, '_asyncio_future_blocking', None) is not None + + +def _format_callbacks(cb): + """helper function for Future.__repr__""" + size = len(cb) + if not size: + cb = '' + + def format_cb(callback): + return events._format_callback_source(callback, ()) + + if size == 1: + cb = format_cb(cb[0]) + elif size == 2: + cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) + elif size > 2: + cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), + size - 2, + format_cb(cb[-1])) + return 'cb=[%s]' % cb + + +def _future_repr_info(future): + # (Future) -> str + """helper function for Future.__repr__""" + info = [future._state.lower()] + if future._state == _FINISHED: + if future._exception is not None: + info.append('exception={!r}'.format(future._exception)) + else: + # use reprlib to limit the length of the output, especially + # for very long strings + result = reprlib.repr(future._result) + info.append('result={}'.format(result)) + if future._callbacks: + info.append(_format_callbacks(future._callbacks)) + if future._source_traceback: + frame = future._source_traceback[-1] + info.append('created at %s:%s' % (frame[0], frame[1])) + return info diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py new file mode 100644 --- /dev/null +++ b/Lib/asyncio/base_tasks.py @@ -0,0 +1,76 @@ +import linecache +import traceback + +from . import base_futures +from . import coroutines + + +def _task_repr_info(task): + info = base_futures._future_repr_info(task) + + if task._must_cancel: + # replace status + info[0] = 'cancelling' + + coro = coroutines._format_coroutine(task._coro) + info.insert(1, 'coro=<%s>' % coro) + + if task._fut_waiter is not None: + info.insert(2, 'wait_for=%r' % task._fut_waiter) + return info + + +def _task_get_stack(task, limit): + frames = [] + try: + # 'async def' coroutines + f = task._coro.cr_frame + except AttributeError: + f = task._coro.gi_frame + if f is not None: + while f is not None: + if limit is not None: + if limit <= 0: + break + limit -= 1 + frames.append(f) + f = f.f_back + frames.reverse() + elif task._exception is not None: + tb = task._exception.__traceback__ + while tb is not None: + if limit is not None: + if limit <= 0: + break + limit -= 1 + frames.append(tb.tb_frame) + tb = tb.tb_next + return frames + + +def _task_print_stack(task, limit, file): + extracted_list = [] + checked = set() + for f in task.get_stack(limit=limit): + lineno = f.f_lineno + co = f.f_code + filename = co.co_filename + name = co.co_name + if filename not in checked: + checked.add(filename) + linecache.checkcache(filename) + line = linecache.getline(filename, lineno, f.f_globals) + extracted_list.append((filename, lineno, name, line)) + exc = task._exception + if not extracted_list: + print('No stack for %r' % task, file=file) + elif exc is not None: + print('Traceback for %r (most recent call last):' % task, + file=file) + else: + print('Stack for %r (most recent call last):' % task, + file=file) + traceback.print_list(extracted_list, file=file) + if exc is not None: + for line in traceback.format_exception_only(exc.__class__, exc): + print(line, file=file, end='') diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -11,7 +11,7 @@ from . import compat from . import events -from . import futures +from . import base_futures from .log import logger @@ -204,7 +204,7 @@ @functools.wraps(func) def coro(*args, **kw): res = func(*args, **kw) - if (futures.isfuture(res) or inspect.isgenerator(res) or + if (base_futures.isfuture(res) or inspect.isgenerator(res) or isinstance(res, CoroWrapper)): res = yield from res elif _AwaitableABC is not None: diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -1,35 +1,32 @@ """A Future class similar to the one in PEP 3148.""" -__all__ = ['CancelledError', 'TimeoutError', - 'InvalidStateError', - 'Future', 'wrap_future', 'isfuture' - ] +__all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', + 'Future', 'wrap_future', 'isfuture'] -import concurrent.futures._base +import concurrent.futures import logging -import reprlib import sys import traceback +from . import base_futures from . import compat from . import events -# States for Future. -_PENDING = 'PENDING' -_CANCELLED = 'CANCELLED' -_FINISHED = 'FINISHED' -Error = concurrent.futures._base.Error -CancelledError = concurrent.futures.CancelledError -TimeoutError = concurrent.futures.TimeoutError +CancelledError = base_futures.CancelledError +InvalidStateError = base_futures.InvalidStateError +TimeoutError = base_futures.TimeoutError +isfuture = base_futures.isfuture + + +_PENDING = base_futures._PENDING +_CANCELLED = base_futures._CANCELLED +_FINISHED = base_futures._FINISHED + STACK_DEBUG = logging.DEBUG - 1 # heavy-duty debugging -class InvalidStateError(Error): - """The operation is not allowed in this state.""" - - class _TracebackLogger: """Helper to log a traceback upon destruction if not cleared. @@ -110,56 +107,6 @@ self.loop.call_exception_handler({'message': msg}) -def isfuture(obj): - """Check for a Future. - - This returns True when obj is a Future instance or is advertising - itself as duck-type compatible by setting _asyncio_future_blocking. - See comment in Future for more details. - """ - return getattr(obj, '_asyncio_future_blocking', None) is not None - - -def _format_callbacks(cb): - """helper function for Future.__repr__""" - size = len(cb) - if not size: - cb = '' - - def format_cb(callback): - return events._format_callback_source(callback, ()) - - if size == 1: - cb = format_cb(cb[0]) - elif size == 2: - cb = '{}, {}'.format(format_cb(cb[0]), format_cb(cb[1])) - elif size > 2: - cb = '{}, <{} more>, {}'.format(format_cb(cb[0]), - size-2, - format_cb(cb[-1])) - return 'cb=[%s]' % cb - - -def _future_repr_info(future): - # (Future) -> str - """helper function for Future.__repr__""" - info = [future._state.lower()] - if future._state == _FINISHED: - if future._exception is not None: - info.append('exception={!r}'.format(future._exception)) - else: - # use reprlib to limit the length of the output, especially - # for very long strings - result = reprlib.repr(future._result) - info.append('result={}'.format(result)) - if future._callbacks: - info.append(_format_callbacks(future._callbacks)) - if future._source_traceback: - frame = future._source_traceback[-1] - info.append('created at %s:%s' % (frame[0], frame[1])) - return info - - class Future: """This class is *almost* compatible with concurrent.futures.Future. @@ -212,7 +159,7 @@ if self._loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) - _repr_info = _future_repr_info + _repr_info = base_futures._future_repr_info def __repr__(self): return '<%s %s>' % (self.__class__.__name__, ' '.join(self._repr_info())) @@ -247,10 +194,10 @@ if self._state != _PENDING: return False self._state = _CANCELLED - self.__schedule_callbacks() + self._schedule_callbacks() return True - def __schedule_callbacks(self): + def _schedule_callbacks(self): """Internal: Ask the event loop to call all callbacks. The callbacks are scheduled to be called as soon as possible. Also @@ -352,7 +299,7 @@ raise InvalidStateError('{}: {!r}'.format(self._state, self)) self._result = result self._state = _FINISHED - self.__schedule_callbacks() + self._schedule_callbacks() def set_exception(self, exception): """Mark the future done and set an exception. @@ -369,7 +316,7 @@ "and cannot be raised into a Future") self._exception = exception self._state = _FINISHED - self.__schedule_callbacks() + self._schedule_callbacks() if compat.PY34: self._log_traceback = True else: diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -9,11 +9,10 @@ import concurrent.futures import functools import inspect -import linecache -import traceback import warnings import weakref +from . import base_tasks from . import compat from . import coroutines from . import events @@ -93,18 +92,7 @@ futures.Future.__del__(self) def _repr_info(self): - info = super()._repr_info() - - if self._must_cancel: - # replace status - info[0] = 'cancelling' - - coro = coroutines._format_coroutine(self._coro) - info.insert(1, 'coro=<%s>' % coro) - - if self._fut_waiter is not None: - info.insert(2, 'wait_for=%r' % self._fut_waiter) - return info + return base_tasks._task_repr_info(self) def get_stack(self, *, limit=None): """Return the list of stack frames for this task's coroutine. @@ -127,31 +115,7 @@ For reasons beyond our control, only one stack frame is returned for a suspended coroutine. """ - frames = [] - try: - # 'async def' coroutines - f = self._coro.cr_frame - except AttributeError: - f = self._coro.gi_frame - if f is not None: - while f is not None: - if limit is not None: - if limit <= 0: - break - limit -= 1 - frames.append(f) - f = f.f_back - frames.reverse() - elif self._exception is not None: - tb = self._exception.__traceback__ - while tb is not None: - if limit is not None: - if limit <= 0: - break - limit -= 1 - frames.append(tb.tb_frame) - tb = tb.tb_next - return frames + return base_tasks._task_get_stack(self, limit) def print_stack(self, *, limit=None, file=None): """Print the stack or traceback for this task's coroutine. @@ -162,31 +126,7 @@ to which the output is written; by default output is written to sys.stderr. """ - extracted_list = [] - checked = set() - for f in self.get_stack(limit=limit): - lineno = f.f_lineno - co = f.f_code - filename = co.co_filename - name = co.co_name - if filename not in checked: - checked.add(filename) - linecache.checkcache(filename) - line = linecache.getline(filename, lineno, f.f_globals) - extracted_list.append((filename, lineno, name, line)) - exc = self._exception - if not extracted_list: - print('No stack for %r' % self, file=file) - elif exc is not None: - print('Traceback for %r (most recent call last):' % self, - file=file) - else: - print('Stack for %r (most recent call last):' % self, - file=file) - traceback.print_list(extracted_list, file=file) - if exc is not None: - for line in traceback.format_exception_only(exc.__class__, exc): - print(line, file=file, end='') + return base_tasks._task_print_stack(self, limit, file) def cancel(self): """Request that this task cancel itself. @@ -316,6 +256,18 @@ self = None # Needed to break cycles when an exception occurs. +_PyTask = Task + + +try: + import _asyncio +except ImportError: + pass +else: + # _CTask is needed for tests. + Task = _CTask = _asyncio.Task + + # wait() and as_completed() similar to those in PEP 3148. FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1,5 +1,6 @@ """Tests for tasks.py.""" +import collections import contextlib import functools import io @@ -14,6 +15,8 @@ import asyncio from asyncio import coroutines +from asyncio import futures +from asyncio import tasks from asyncio import test_utils try: from test import support @@ -72,14 +75,25 @@ pass -class TaskTests(test_utils.TestCase): +class BaseTaskTests: + + Task = None + Future = None + + def new_task(self, loop, coro): + return self.__class__.Task(coro, loop=loop) + + def new_future(self, loop): + return self.__class__.Future(loop=loop) def setUp(self): self.loop = self.new_test_loop() + self.loop.set_task_factory(self.new_task) + self.loop.create_future = lambda: self.new_future(self.loop) def test_other_loop_future(self): other_loop = asyncio.new_event_loop() - fut = asyncio.Future(loop=other_loop) + fut = self.new_future(other_loop) @asyncio.coroutine def run(fut): @@ -107,7 +121,7 @@ @asyncio.coroutine def notmuch(): return 'ok' - t = asyncio.Task(notmuch(), loop=self.loop) + t = self.new_task(self.loop, notmuch()) self.loop.run_until_complete(t) self.assertTrue(t.done()) self.assertEqual(t.result(), 'ok') @@ -115,7 +129,7 @@ loop = asyncio.new_event_loop() self.set_event_loop(loop) - t = asyncio.Task(notmuch(), loop=loop) + t = self.new_task(loop, notmuch()) self.assertIs(t._loop, loop) loop.run_until_complete(t) loop.close() @@ -138,7 +152,7 @@ loop.close() def test_ensure_future_future(self): - f_orig = asyncio.Future(loop=self.loop) + f_orig = self.new_future(self.loop) f_orig.set_result('ko') f = asyncio.ensure_future(f_orig) @@ -162,7 +176,7 @@ @asyncio.coroutine def notmuch(): return 'ok' - t_orig = asyncio.Task(notmuch(), loop=self.loop) + t_orig = self.new_task(self.loop, notmuch()) t = asyncio.ensure_future(t_orig) self.loop.run_until_complete(t) self.assertTrue(t.done()) @@ -203,7 +217,7 @@ asyncio.ensure_future('ok') def test_async_warning(self): - f = asyncio.Future(loop=self.loop) + f = self.new_future(self.loop) with self.assertWarnsRegex(DeprecationWarning, 'function is deprecated, use ensure_'): self.assertIs(f, asyncio.async(f)) @@ -250,8 +264,8 @@ # test coroutine function self.assertEqual(notmuch.__name__, 'notmuch') if PY35: - self.assertEqual(notmuch.__qualname__, - 'TaskTests.test_task_repr..notmuch') + self.assertRegex(notmuch.__qualname__, + r'\w+.test_task_repr..notmuch') self.assertEqual(notmuch.__module__, __name__) filename, lineno = test_utils.get_function_source(notmuch) @@ -260,7 +274,7 @@ # test coroutine object gen = notmuch() if coroutines._DEBUG or PY35: - coro_qualname = 'TaskTests.test_task_repr..notmuch' + coro_qualname = 'BaseTaskTests.test_task_repr..notmuch' else: coro_qualname = 'notmuch' self.assertEqual(gen.__name__, 'notmuch') @@ -269,7 +283,7 @@ coro_qualname) # test pending Task - t = asyncio.Task(gen, loop=self.loop) + t = self.new_task(self.loop, gen) t.add_done_callback(Dummy()) coro = format_coroutine(coro_qualname, 'running', src, @@ -291,7 +305,7 @@ '' % coro) # test finished Task - t = asyncio.Task(notmuch(), loop=self.loop) + t = self.new_task(self.loop, notmuch()) self.loop.run_until_complete(t) coro = format_coroutine(coro_qualname, 'done', src, t._source_traceback) @@ -310,9 +324,9 @@ # test coroutine function self.assertEqual(notmuch.__name__, 'notmuch') if PY35: - self.assertEqual(notmuch.__qualname__, - 'TaskTests.test_task_repr_coro_decorator' - '..notmuch') + self.assertRegex(notmuch.__qualname__, + r'\w+.test_task_repr_coro_decorator' + r'\.\.notmuch') self.assertEqual(notmuch.__module__, __name__) # test coroutine object @@ -322,7 +336,7 @@ # function, as expected, and have a qualified name (__qualname__ # attribute). coro_name = 'notmuch' - coro_qualname = ('TaskTests.test_task_repr_coro_decorator' + coro_qualname = ('BaseTaskTests.test_task_repr_coro_decorator' '..notmuch') else: # On Python < 3.5, generators inherit the name of the code, not of @@ -350,7 +364,7 @@ self.assertEqual(repr(gen), '' % coro) # test pending Task - t = asyncio.Task(gen, loop=self.loop) + t = self.new_task(self.loop, gen) t.add_done_callback(Dummy()) # format the coroutine object @@ -373,8 +387,8 @@ def wait_for(fut): return (yield from fut) - fut = asyncio.Future(loop=self.loop) - task = asyncio.Task(wait_for(fut), loop=self.loop) + fut = self.new_future(self.loop) + task = self.new_task(self.loop, wait_for(fut)) test_utils.run_briefly(self.loop) self.assertRegex(repr(task), '' % re.escape(repr(fut))) @@ -400,10 +414,11 @@ self.addCleanup(task._coro.close) coro_repr = repr(task._coro) - expected = ('.func(1)() running, ') - self.assertTrue(coro_repr.startswith(expected), - coro_repr) + expected = ( + r'\.func\(1\)\(\) running, ' + ) + self.assertRegex(coro_repr, expected) def test_task_basics(self): @asyncio.coroutine @@ -437,7 +452,7 @@ yield from asyncio.sleep(10.0, loop=loop) return 12 - t = asyncio.Task(task(), loop=loop) + t = self.new_task(loop, task()) loop.call_soon(t.cancel) with self.assertRaises(asyncio.CancelledError): loop.run_until_complete(t) @@ -452,7 +467,7 @@ yield return 12 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) # start coro t.cancel() self.assertRaises( @@ -462,14 +477,14 @@ self.assertFalse(t.cancel()) def test_cancel_inner_future(self): - f = asyncio.Future(loop=self.loop) + f = self.new_future(self.loop) @asyncio.coroutine def task(): yield from f return 12 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) # start task f.cancel() with self.assertRaises(asyncio.CancelledError): @@ -478,14 +493,14 @@ self.assertTrue(t.cancelled()) def test_cancel_both_task_and_inner_future(self): - f = asyncio.Future(loop=self.loop) + f = self.new_future(self.loop) @asyncio.coroutine def task(): yield from f return 12 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) f.cancel() @@ -499,8 +514,8 @@ self.assertTrue(t.cancelled()) def test_cancel_task_catching(self): - fut1 = asyncio.Future(loop=self.loop) - fut2 = asyncio.Future(loop=self.loop) + fut1 = self.new_future(self.loop) + fut2 = self.new_future(self.loop) @asyncio.coroutine def task(): @@ -510,7 +525,7 @@ except asyncio.CancelledError: return 42 - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) self.assertIs(t._fut_waiter, fut1) # White-box test. fut1.set_result(None) @@ -523,9 +538,9 @@ self.assertFalse(t.cancelled()) def test_cancel_task_ignoring(self): - fut1 = asyncio.Future(loop=self.loop) - fut2 = asyncio.Future(loop=self.loop) - fut3 = asyncio.Future(loop=self.loop) + fut1 = self.new_future(self.loop) + fut2 = self.new_future(self.loop) + fut3 = self.new_future(self.loop) @asyncio.coroutine def task(): @@ -537,7 +552,7 @@ res = yield from fut3 return res - t = asyncio.Task(task(), loop=self.loop) + t = self.new_task(self.loop, task()) test_utils.run_briefly(self.loop) self.assertIs(t._fut_waiter, fut1) # White-box test. fut1.set_result(None) @@ -565,7 +580,7 @@ yield from asyncio.sleep(100, loop=loop) return 12 - t = asyncio.Task(task(), loop=loop) + t = self.new_task(loop, task()) self.assertRaises( asyncio.CancelledError, loop.run_until_complete, t) self.assertTrue(t.done()) @@ -598,7 +613,7 @@ if x == 2: loop.stop() - t = asyncio.Task(task(), loop=loop) + t = self.new_task(loop, task()) with self.assertRaises(RuntimeError) as cm: loop.run_until_complete(t) self.assertEqual(str(cm.exception), @@ -636,7 +651,7 @@ foo_running = False return 'done' - fut = asyncio.Task(foo(), loop=loop) + fut = self.new_task(loop, foo()) with self.assertRaises(asyncio.TimeoutError): loop.run_until_complete(asyncio.wait_for(fut, 0.1, loop=loop)) @@ -676,7 +691,7 @@ asyncio.set_event_loop(loop) try: - fut = asyncio.Task(foo(), loop=loop) + fut = self.new_task(loop, foo()) with self.assertRaises(asyncio.TimeoutError): loop.run_until_complete(asyncio.wait_for(fut, 0.01)) finally: @@ -695,7 +710,7 @@ loop = self.new_test_loop(gen) - fut = asyncio.Future(loop=loop) + fut = self.new_future(loop) task = asyncio.wait_for(fut, timeout=0.2, loop=loop) loop.call_later(0.1, fut.set_result, "ok") res = loop.run_until_complete(task) @@ -712,8 +727,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.15, loop=loop)) @asyncio.coroutine def foo(): @@ -722,12 +737,12 @@ self.assertEqual(pending, set()) return 42 - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertEqual(res, 42) self.assertAlmostEqual(0.15, loop.time()) # Doing it again should take no time and exercise a different path. - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) self.assertEqual(res, 42) @@ -742,8 +757,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.01, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.015, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.01, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.015, loop=loop)) @asyncio.coroutine def foo(): @@ -754,7 +769,7 @@ asyncio.set_event_loop(loop) res = loop.run_until_complete( - asyncio.Task(foo(), loop=loop)) + self.new_task(loop, foo())) self.assertEqual(res, 42) @@ -764,9 +779,9 @@ return s c = coro('test') - task = asyncio.Task( - asyncio.wait([c, c, coro('spam')], loop=self.loop), - loop=self.loop) + task =self.new_task( + self.loop, + asyncio.wait([c, c, coro('spam')], loop=self.loop)) done, pending = self.loop.run_until_complete(task) @@ -797,12 +812,12 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - task = asyncio.Task( + a = self.new_task(loop, asyncio.sleep(10.0, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + task = self.new_task( + loop, asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, - loop=loop), - loop=loop) + loop=loop)) done, pending = loop.run_until_complete(task) self.assertEqual({b}, done) @@ -829,12 +844,12 @@ yield yield - a = asyncio.Task(coro1(), loop=self.loop) - b = asyncio.Task(coro2(), loop=self.loop) - task = asyncio.Task( + a = self.new_task(self.loop, coro1()) + b = self.new_task(self.loop, coro2()) + task = self.new_task( + self.loop, asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, - loop=self.loop), - loop=self.loop) + loop=self.loop)) done, pending = self.loop.run_until_complete(task) self.assertEqual({a, b}, done) @@ -853,17 +868,17 @@ loop = self.new_test_loop(gen) # first_exception, task already has exception - a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(10.0, loop=loop)) @asyncio.coroutine def exc(): raise ZeroDivisionError('err') - b = asyncio.Task(exc(), loop=loop) - task = asyncio.Task( + b = self.new_task(loop, exc()) + task = self.new_task( + loop, asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, - loop=loop), - loop=loop) + loop=loop)) done, pending = loop.run_until_complete(task) self.assertEqual({b}, done) @@ -886,14 +901,14 @@ loop = self.new_test_loop(gen) # first_exception, exception during waiting - a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(10.0, loop=loop)) @asyncio.coroutine def exc(): yield from asyncio.sleep(0.01, loop=loop) raise ZeroDivisionError('err') - b = asyncio.Task(exc(), loop=loop) + b = self.new_task(loop, exc()) task = asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, loop=loop) @@ -917,14 +932,14 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) @asyncio.coroutine def sleeper(): yield from asyncio.sleep(0.15, loop=loop) raise ZeroDivisionError('really') - b = asyncio.Task(sleeper(), loop=loop) + b = self.new_task(loop, sleeper()) @asyncio.coroutine def foo(): @@ -934,10 +949,10 @@ errors = set(f for f in done if f.exception() is not None) self.assertEqual(len(errors), 1) - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) def test_wait_with_timeout(self): @@ -953,8 +968,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.15, loop=loop)) @asyncio.coroutine def foo(): @@ -963,7 +978,7 @@ self.assertEqual(done, set([a])) self.assertEqual(pending, set([b])) - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.11, loop.time()) # move forward to close generator @@ -983,8 +998,8 @@ loop = self.new_test_loop(gen) - a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) + a = self.new_task(loop, asyncio.sleep(0.1, loop=loop)) + b = self.new_task(loop, asyncio.sleep(0.15, loop=loop)) done, pending = loop.run_until_complete( asyncio.wait([b, a], timeout=0.1, loop=loop)) @@ -1032,14 +1047,14 @@ values.append((yield from f)) return values - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) self.assertTrue('a' in res[:2]) self.assertTrue('b' in res[:2]) self.assertEqual(res[2], 'c') # Doing it again should take no time and exercise a different path. - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) def test_as_completed_with_timeout(self): @@ -1068,7 +1083,7 @@ values.append((2, exc)) return values - res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + res = loop.run_until_complete(self.new_task(loop, foo())) self.assertEqual(len(res), 2, res) self.assertEqual(res[0], (1, 'a')) self.assertEqual(res[1][0], 2) @@ -1096,7 +1111,7 @@ v = yield from f self.assertEqual(v, 'a') - loop.run_until_complete(asyncio.Task(foo(), loop=loop)) + loop.run_until_complete(self.new_task(loop, foo())) def test_as_completed_reverse_wait(self): @@ -1156,7 +1171,7 @@ result.append((yield from f)) return result - fut = asyncio.Task(runner(), loop=self.loop) + fut = self.new_task(self.loop, runner()) self.loop.run_until_complete(fut) result = fut.result() self.assertEqual(set(result), {'ham', 'spam'}) @@ -1179,7 +1194,7 @@ res = yield from asyncio.sleep(dt/2, arg, loop=loop) return res - t = asyncio.Task(sleeper(0.1, 'yeah'), loop=loop) + t = self.new_task(loop, sleeper(0.1, 'yeah')) loop.run_until_complete(t) self.assertTrue(t.done()) self.assertEqual(t.result(), 'yeah') @@ -1194,8 +1209,7 @@ loop = self.new_test_loop(gen) - t = asyncio.Task(asyncio.sleep(10.0, 'yeah', loop=loop), - loop=loop) + t = self.new_task(loop, asyncio.sleep(10.0, 'yeah', loop=loop)) handle = None orig_call_later = loop.call_later @@ -1231,7 +1245,7 @@ @asyncio.coroutine def doit(): - sleeper = asyncio.Task(sleep(5000), loop=loop) + sleeper = self.new_task(loop, sleep(5000)) loop.call_later(0.1, sleeper.cancel) try: yield from sleeper @@ -1245,13 +1259,13 @@ self.assertAlmostEqual(0.1, loop.time()) def test_task_cancel_waiter_future(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) @asyncio.coroutine def coro(): yield from fut - task = asyncio.Task(coro(), loop=self.loop) + task = self.new_task(self.loop, coro()) test_utils.run_briefly(self.loop) self.assertIs(task._fut_waiter, fut) @@ -1268,7 +1282,7 @@ return 'ko' gen = notmuch() - task = asyncio.Task(gen, loop=self.loop) + task = self.new_task(self.loop, gen) task.set_result('ok') self.assertRaises(AssertionError, task._step) @@ -1304,7 +1318,7 @@ nonlocal result result = yield from fut - t = asyncio.Task(wait_for_future(), loop=self.loop) + t = self.new_task(self.loop, wait_for_future()) test_utils.run_briefly(self.loop) self.assertTrue(fut.cb_added) @@ -1320,7 +1334,7 @@ def notmutch(): raise BaseException() - task = asyncio.Task(notmutch(), loop=self.loop) + task = self.new_task(self.loop, notmutch()) self.assertRaises(BaseException, task._step) self.assertTrue(task.done()) @@ -1348,7 +1362,7 @@ except asyncio.CancelledError: raise base_exc - task = asyncio.Task(notmutch(), loop=loop) + task = self.new_task(loop, notmutch()) test_utils.run_briefly(loop) task.cancel() @@ -1376,7 +1390,7 @@ self.assertTrue(asyncio.iscoroutinefunction(fn2)) def test_yield_vs_yield_from(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) @asyncio.coroutine def wait_for_future(): @@ -1420,7 +1434,7 @@ self.assertEqual(res, 'test') def test_coroutine_non_gen_function_return_future(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) @asyncio.coroutine def func(): @@ -1430,49 +1444,53 @@ def coro(): fut.set_result('test') - t1 = asyncio.Task(func(), loop=self.loop) - t2 = asyncio.Task(coro(), loop=self.loop) + t1 = self.new_task(self.loop, func()) + t2 = self.new_task(self.loop, coro()) res = self.loop.run_until_complete(t1) self.assertEqual(res, 'test') self.assertIsNone(t2.result()) def test_current_task(self): - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) + Task = self.__class__.Task + + self.assertIsNone(Task.current_task(loop=self.loop)) @asyncio.coroutine def coro(loop): - self.assertTrue(asyncio.Task.current_task(loop=loop) is task) - - task = asyncio.Task(coro(self.loop), loop=self.loop) + self.assertTrue(Task.current_task(loop=loop) is task) + + task = self.new_task(self.loop, coro(self.loop)) self.loop.run_until_complete(task) - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) + self.assertIsNone(Task.current_task(loop=self.loop)) def test_current_task_with_interleaving_tasks(self): - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) - - fut1 = asyncio.Future(loop=self.loop) - fut2 = asyncio.Future(loop=self.loop) + Task = self.__class__.Task + + self.assertIsNone(Task.current_task(loop=self.loop)) + + fut1 = self.new_future(self.loop) + fut2 = self.new_future(self.loop) @asyncio.coroutine def coro1(loop): - self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) + self.assertTrue(Task.current_task(loop=loop) is task1) yield from fut1 - self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) + self.assertTrue(Task.current_task(loop=loop) is task1) fut2.set_result(True) @asyncio.coroutine def coro2(loop): - self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) + self.assertTrue(Task.current_task(loop=loop) is task2) fut1.set_result(True) yield from fut2 - self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) - - task1 = asyncio.Task(coro1(self.loop), loop=self.loop) - task2 = asyncio.Task(coro2(self.loop), loop=self.loop) + self.assertTrue(Task.current_task(loop=loop) is task2) + + task1 = self.new_task(self.loop, coro1(self.loop)) + task2 = self.new_task(self.loop, coro2(self.loop)) self.loop.run_until_complete(asyncio.wait((task1, task2), loop=self.loop)) - self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) + self.assertIsNone(Task.current_task(loop=self.loop)) # Some thorough tests for cancellation propagation through # coroutines, tasks and wait(). @@ -1480,7 +1498,7 @@ def test_yield_future_passes_cancel(self): # Cancelling outer() cancels inner() cancels waiter. proof = 0 - waiter = asyncio.Future(loop=self.loop) + waiter = self.new_future(self.loop) @asyncio.coroutine def inner(): @@ -1514,7 +1532,7 @@ # Cancelling outer() makes wait() return early, leaves inner() # running. proof = 0 - waiter = asyncio.Future(loop=self.loop) + waiter = self.new_future(self.loop) @asyncio.coroutine def inner(): @@ -1538,14 +1556,14 @@ self.assertEqual(proof, 1) def test_shield_result(self): - inner = asyncio.Future(loop=self.loop) + inner = self.new_future(self.loop) outer = asyncio.shield(inner) inner.set_result(42) res = self.loop.run_until_complete(outer) self.assertEqual(res, 42) def test_shield_exception(self): - inner = asyncio.Future(loop=self.loop) + inner = self.new_future(self.loop) outer = asyncio.shield(inner) test_utils.run_briefly(self.loop) exc = RuntimeError('expected') @@ -1554,7 +1572,7 @@ self.assertIs(outer.exception(), exc) def test_shield_cancel(self): - inner = asyncio.Future(loop=self.loop) + inner = self.new_future(self.loop) outer = asyncio.shield(inner) test_utils.run_briefly(self.loop) inner.cancel() @@ -1562,7 +1580,7 @@ self.assertTrue(outer.cancelled()) def test_shield_shortcut(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) fut.set_result(42) res = self.loop.run_until_complete(asyncio.shield(fut)) self.assertEqual(res, 42) @@ -1570,7 +1588,7 @@ def test_shield_effect(self): # Cancelling outer() does not affect inner(). proof = 0 - waiter = asyncio.Future(loop=self.loop) + waiter = self.new_future(self.loop) @asyncio.coroutine def inner(): @@ -1594,8 +1612,8 @@ self.assertEqual(proof, 1) def test_shield_gather(self): - child1 = asyncio.Future(loop=self.loop) - child2 = asyncio.Future(loop=self.loop) + child1 = self.new_future(self.loop) + child2 = self.new_future(self.loop) parent = asyncio.gather(child1, child2, loop=self.loop) outer = asyncio.shield(parent, loop=self.loop) test_utils.run_briefly(self.loop) @@ -1608,8 +1626,8 @@ self.assertEqual(parent.result(), [1, 2]) def test_gather_shield(self): - child1 = asyncio.Future(loop=self.loop) - child2 = asyncio.Future(loop=self.loop) + child1 = self.new_future(self.loop) + child2 = self.new_future(self.loop) inner1 = asyncio.shield(child1, loop=self.loop) inner2 = asyncio.shield(child2, loop=self.loop) parent = asyncio.gather(inner1, inner2, loop=self.loop) @@ -1625,7 +1643,7 @@ test_utils.run_briefly(self.loop) def test_as_completed_invalid_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) # as_completed() expects a list of futures, not a future instance self.assertRaises(TypeError, self.loop.run_until_complete, @@ -1636,7 +1654,7 @@ coro.close() def test_wait_invalid_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) # wait() expects a list of futures, not a future instance self.assertRaises(TypeError, self.loop.run_until_complete, @@ -1663,7 +1681,7 @@ yield from fut # A completed Future used to run the coroutine. - fut = asyncio.Future(loop=self.loop) + fut = self.new_future(self.loop) fut.set_result(None) # Call the coroutine. @@ -1697,15 +1715,15 @@ @asyncio.coroutine def t2(): - f = asyncio.Future(loop=self.loop) - asyncio.Task(t3(f), loop=self.loop) + f = self.new_future(self.loop) + self.new_task(self.loop, t3(f)) return (yield from f) @asyncio.coroutine def t3(f): f.set_result((1, 2, 3)) - task = asyncio.Task(t1(), loop=self.loop) + task = self.new_task(self.loop, t1()) val = self.loop.run_until_complete(task) self.assertEqual(val, (1, 2, 3)) @@ -1768,9 +1786,11 @@ @unittest.skipUnless(PY34, 'need python 3.4 or later') def test_log_destroyed_pending_task(self): + Task = self.__class__.Task + @asyncio.coroutine def kill_me(loop): - future = asyncio.Future(loop=loop) + future = self.new_future(loop) yield from future # at this point, the only reference to kill_me() task is # the Task._wakeup() method in future._callbacks @@ -1783,7 +1803,7 @@ # schedule the task coro = kill_me(self.loop) task = asyncio.ensure_future(coro, loop=self.loop) - self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), {task}) + self.assertEqual(Task.all_tasks(loop=self.loop), {task}) # execute the task so it waits for future self.loop._run_once() @@ -1798,7 +1818,7 @@ # no more reference to kill_me() task: the task is destroyed by the GC support.gc_collect() - self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), set()) + self.assertEqual(Task.all_tasks(loop=self.loop), set()) mock_handler.assert_called_with(self.loop, { 'message': 'Task was destroyed but it is pending!', @@ -1863,10 +1883,10 @@ def test_task_source_traceback(self): self.loop.set_debug(True) - task = asyncio.Task(coroutine_function(), loop=self.loop) + task = self.new_task(self.loop, coroutine_function()) lineno = sys._getframe().f_lineno - 1 self.assertIsInstance(task._source_traceback, list) - self.assertEqual(task._source_traceback[-1][:3], + self.assertEqual(task._source_traceback[-2][:3], (__file__, lineno, 'test_task_source_traceback')) @@ -1878,7 +1898,7 @@ @asyncio.coroutine def blocking_coroutine(): - fut = asyncio.Future(loop=loop) + fut = self.new_future(loop) # Block: fut result is never set yield from fut @@ -1905,7 +1925,7 @@ loop = asyncio.new_event_loop() self.addCleanup(loop.close) - fut = asyncio.Future(loop=loop) + fut = self.new_future(loop) # The indirection fut->child_coro is needed since otherwise the # gathering task is done at the same time as the child future def child_coro(): @@ -1929,6 +1949,157 @@ self.assertFalse(gather_task.cancelled()) self.assertEqual(gather_task.result(), [42]) + @mock.patch('asyncio.base_events.logger') + def test_error_in_call_soon(self, m_log): + def call_soon(callback, *args): + raise ValueError + self.loop.call_soon = call_soon + + @asyncio.coroutine + def coro(): + pass + + self.assertFalse(m_log.error.called) + + with self.assertRaises(ValueError): + self.new_task(self.loop, coro()) + + self.assertTrue(m_log.error.called) + message = m_log.error.call_args[0][0] + self.assertIn('Task was destroyed but it is pending', message) + + self.assertEqual(self.Task.all_tasks(self.loop), set()) + + +def add_subclass_tests(cls): + BaseTask = cls.Task + BaseFuture = cls.Future + + if BaseTask is None or BaseFuture is None: + return cls + + class CommonFuture: + def __init__(self, *args, **kwargs): + self.calls = collections.defaultdict(lambda: 0) + super().__init__(*args, **kwargs) + + def _schedule_callbacks(self): + self.calls['_schedule_callbacks'] += 1 + return super()._schedule_callbacks() + + def add_done_callback(self, *args): + self.calls['add_done_callback'] += 1 + return super().add_done_callback(*args) + + class Task(CommonFuture, BaseTask): + def _step(self, *args): + self.calls['_step'] += 1 + return super()._step(*args) + + def _wakeup(self, *args): + self.calls['_wakeup'] += 1 + return super()._wakeup(*args) + + class Future(CommonFuture, BaseFuture): + pass + + def test_subclasses_ctask_cfuture(self): + fut = self.Future(loop=self.loop) + + async def func(): + self.loop.call_soon(lambda: fut.set_result('spam')) + return await fut + + task = self.Task(func(), loop=self.loop) + + result = self.loop.run_until_complete(task) + + self.assertEqual(result, 'spam') + + self.assertEqual( + dict(task.calls), + {'_step': 2, '_wakeup': 1, 'add_done_callback': 1, + '_schedule_callbacks': 1}) + + self.assertEqual( + dict(fut.calls), + {'add_done_callback': 1, '_schedule_callbacks': 1}) + + # Add patched Task & Future back to the test case + cls.Task = Task + cls.Future = Future + + # Add an extra unit-test + cls.test_subclasses_ctask_cfuture = test_subclasses_ctask_cfuture + + # Disable the "test_task_source_traceback" test + # (the test is hardcoded for a particular call stack, which + # is slightly different for Task subclasses) + cls.test_task_source_traceback = None + + return cls + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CTask_CFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + Future = getattr(futures, '_CFuture', None) + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') + at add_subclass_tests +class CTask_CFuture_SubclassTests(BaseTaskTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + Future = getattr(futures, '_CFuture', None) + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CTask_PyFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + Future = futures._PyFuture + + + at unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class PyTask_CFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = tasks._PyTask + Future = getattr(futures, '_CFuture', None) + + +class PyTask_PyFuture_Tests(BaseTaskTests, test_utils.TestCase): + Task = tasks._PyTask + Future = futures._PyFuture + + + at add_subclass_tests +class PyTask_PyFuture_SubclassTests(BaseTaskTests, test_utils.TestCase): + Task = tasks._PyTask + Future = futures._PyFuture + + +class GenericTaskTests(test_utils.TestCase): + + def test_future_subclass(self): + self.assertTrue(issubclass(asyncio.Task, asyncio.Future)) + + def test_asyncio_module_compiled(self): + # Because of circular imports it's easy to make _asyncio + # module non-importable. This is a simple test that will + # fail on systems where C modules were successfully compiled + # (hence the test for _functools), but _asyncio somehow didn't. + try: + import _functools + except ImportError: + pass + else: + try: + import _asyncio + except ImportError: + self.fail('_asyncio module is missing') + class GatherTestsBase: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,8 @@ threadpool executor. Initial patch by Hans Lawrenz. +- Issue #28544: Implement asyncio.Task in C. + Windows ------- diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2,20 +2,35 @@ #include "structmember.h" +/*[clinic input] +module _asyncio +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8fd17862aa989c69]*/ + + /* identifiers used from some functions */ +_Py_IDENTIFIER(add_done_callback); _Py_IDENTIFIER(call_soon); +_Py_IDENTIFIER(cancel); +_Py_IDENTIFIER(send); +_Py_IDENTIFIER(throw); +_Py_IDENTIFIER(_step); +_Py_IDENTIFIER(_schedule_callbacks); +_Py_IDENTIFIER(_wakeup); /* State of the _asyncio module */ +static PyObject *all_tasks; +static PyDictObject *current_tasks; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; -static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_future_repr_info_func; +static PyObject *asyncio_task_repr_info_func; +static PyObject *asyncio_task_get_stack_func; +static PyObject *asyncio_task_print_stack_func; static PyObject *asyncio_InvalidStateError; static PyObject *asyncio_CancelledError; - - -/* Get FutureIter from Future */ -static PyObject* new_future_iter(PyObject *fut); +static PyObject *inspect_isgenerator; typedef enum { @@ -24,24 +39,57 @@ STATE_FINISHED } fut_state; +#define FutureObj_HEAD(prefix) \ + PyObject_HEAD \ + PyObject *prefix##_loop; \ + PyObject *prefix##_callbacks; \ + PyObject *prefix##_exception; \ + PyObject *prefix##_result; \ + PyObject *prefix##_source_tb; \ + fut_state prefix##_state; \ + int prefix##_log_tb; \ + int prefix##_blocking; \ + PyObject *dict; \ + PyObject *prefix##_weakreflist; + +typedef struct { + FutureObj_HEAD(fut) +} FutureObj; + +typedef struct { + FutureObj_HEAD(task) + PyObject *task_fut_waiter; + PyObject *task_coro; + int task_must_cancel; + int task_log_destroy_pending; +} TaskObj; typedef struct { PyObject_HEAD - PyObject *fut_loop; - PyObject *fut_callbacks; - PyObject *fut_exception; - PyObject *fut_result; - PyObject *fut_source_tb; - fut_state fut_state; - int fut_log_tb; - int fut_blocking; - PyObject *dict; - PyObject *fut_weakreflist; -} FutureObj; + TaskObj *sw_task; + PyObject *sw_arg; +} TaskSendMethWrapper; +typedef struct { + PyObject_HEAD + TaskObj *ww_task; +} TaskWakeupMethWrapper; + + +#include "clinic/_asynciomodule.c.h" + + +/*[clinic input] +class _asyncio.Future "FutureObj *" "&Future_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=00d3e4abca711e0f]*/ + +/* Get FutureIter from Future */ +static PyObject* future_new_iter(PyObject *); +static inline int future_call_schedule_callbacks(FutureObj *); static int -_schedule_callbacks(FutureObj *fut) +future_schedule_callbacks(FutureObj *fut) { Py_ssize_t len; PyObject* iters; @@ -87,16 +135,11 @@ } static int -FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +future_init(FutureObj *fut, PyObject *loop) { - static char *kwlist[] = {"loop", NULL}; - PyObject *loop = NULL; PyObject *res = NULL; _Py_IDENTIFIER(get_debug); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { - return -1; - } if (loop == NULL || loop == Py_None) { loop = PyObject_CallObject(asyncio_get_event_loop, NULL); if (loop == NULL) { @@ -128,106 +171,12 @@ if (fut->fut_callbacks == NULL) { return -1; } + return 0; } -static int -FutureObj_clear(FutureObj *fut) -{ - Py_CLEAR(fut->fut_loop); - Py_CLEAR(fut->fut_callbacks); - Py_CLEAR(fut->fut_result); - Py_CLEAR(fut->fut_exception); - Py_CLEAR(fut->fut_source_tb); - Py_CLEAR(fut->dict); - return 0; -} - -static int -FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) -{ - Py_VISIT(fut->fut_loop); - Py_VISIT(fut->fut_callbacks); - Py_VISIT(fut->fut_result); - Py_VISIT(fut->fut_exception); - Py_VISIT(fut->fut_source_tb); - Py_VISIT(fut->dict); - return 0; -} - -PyDoc_STRVAR(pydoc_result, - "Return the result this future represents.\n" - "\n" - "If the future has been cancelled, raises CancelledError. If the\n" - "future's result isn't yet available, raises InvalidStateError. If\n" - "the future is done and has an exception set, this exception is raised." -); - static PyObject * -FutureObj_result(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - fut->fut_log_tb = 0; - if (fut->fut_exception != NULL) { - PyObject *type = NULL; - type = PyExceptionInstance_Class(fut->fut_exception); - PyErr_SetObject(type, fut->fut_exception); - return NULL; - } - - Py_INCREF(fut->fut_result); - return fut->fut_result; -} - -PyDoc_STRVAR(pydoc_exception, - "Return the exception that was set on this future.\n" - "\n" - "The exception (or None if no exception was set) is returned only if\n" - "the future is done. If the future has been cancelled, raises\n" - "CancelledError. If the future isn't done yet, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_exception(FutureObj *fut, PyObject *arg) -{ - if (fut->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); - return NULL; - } - - if (fut->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); - return NULL; - } - - if (fut->fut_exception != NULL) { - fut->fut_log_tb = 0; - Py_INCREF(fut->fut_exception); - return fut->fut_exception; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pydoc_set_result, - "Mark the future done and set its result.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - -static PyObject * -FutureObj_set_result(FutureObj *fut, PyObject *res) +future_set_result(FutureObj *fut, PyObject *res) { if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); @@ -238,21 +187,14 @@ fut->fut_result = res; fut->fut_state = STATE_FINISHED; - if (_schedule_callbacks(fut) == -1) { + if (future_call_schedule_callbacks(fut) == -1) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(pydoc_set_exception, - "Mark the future done and set an exception.\n" - "\n" - "If the future is already done when this method is called, raises\n" - "InvalidStateError." -); - static PyObject * -FutureObj_set_exception(FutureObj *fut, PyObject *exc) +future_set_exception(FutureObj *fut, PyObject *exc) { PyObject *exc_val = NULL; @@ -287,7 +229,7 @@ fut->fut_exception = exc_val; fut->fut_state = STATE_FINISHED; - if (_schedule_callbacks(fut) == -1) { + if (future_call_schedule_callbacks(fut) == -1) { return NULL; } @@ -295,16 +237,50 @@ Py_RETURN_NONE; } -PyDoc_STRVAR(pydoc_add_done_callback, - "Add a callback to be run when the future becomes done.\n" - "\n" - "The callback is called with a single argument - the future object. If\n" - "the future is already done when this is called, the callback is\n" - "scheduled with call_soon."; -); +static int +future_get_result(FutureObj *fut, PyObject **result) +{ + PyObject *exc; + + if (fut->fut_state == STATE_CANCELLED) { + exc = _PyObject_CallNoArg(asyncio_CancelledError); + if (exc == NULL) { + return -1; + } + *result = exc; + return 1; + } + + if (fut->fut_state != STATE_FINISHED) { + PyObject *msg = PyUnicode_FromString("Result is not ready."); + if (msg == NULL) { + return -1; + } + + exc = _PyObject_CallArg1(asyncio_InvalidStateError, msg); + Py_DECREF(msg); + if (exc == NULL) { + return -1; + } + + *result = exc; + return 1; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + Py_INCREF(fut->fut_exception); + *result = fut->fut_exception; + return 1; + } + + Py_INCREF(fut->fut_result); + *result = fut->fut_result; + return 0; +} static PyObject * -FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +future_add_done_callback(FutureObj *fut, PyObject *arg) { if (fut->fut_state != STATE_PENDING) { PyObject *handle = _PyObject_CallMethodId( @@ -326,19 +302,216 @@ Py_RETURN_NONE; } -PyDoc_STRVAR(pydoc_remove_done_callback, - "Remove all instances of a callback from the \"call when done\" list.\n" - "\n" - "Returns the number of callbacks removed." -); +static PyObject * +future_cancel(FutureObj *fut) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (future_call_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +/*[clinic input] +_asyncio.Future.__init__ + + * + loop: 'O' = NULL + +This class is *almost* compatible with concurrent.futures.Future. + + Differences: + + - result() and exception() do not take a timeout argument and + raise an exception when the future isn't done yet. + + - Callbacks registered with add_done_callback() are always called + via the event loop's call_soon_threadsafe(). + + - This class is not compatible with the wait() and as_completed() + methods in the concurrent.futures package. +[clinic start generated code]*/ + +static int +_asyncio_Future___init___impl(FutureObj *self, PyObject *loop) +/*[clinic end generated code: output=9ed75799eaccb5d6 input=8e1681f23605be2d]*/ + +{ + return future_init(self, loop); +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +/*[clinic input] +_asyncio.Future.result + +Return the result this future represents. + +If the future has been cancelled, raises CancelledError. If the +future's result isn't yet available, raises InvalidStateError. If +the future is done and has an exception set, this exception is raised. +[clinic start generated code]*/ static PyObject * -FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +_asyncio_Future_result_impl(FutureObj *self) +/*[clinic end generated code: output=f35f940936a4b1e5 input=49ecf9cf5ec50dc5]*/ +{ + PyObject *result; + int res = future_get_result(self, &result); + + if (res == -1) { + return NULL; + } + + if (res == 0) { + return result; + } + + assert(res == 1); + + PyErr_SetObject(PyExceptionInstance_Class(result), result); + Py_DECREF(result); + return NULL; +} + +/*[clinic input] +_asyncio.Future.exception + +Return the exception that was set on this future. + +The exception (or None if no exception was set) is returned only if +the future is done. If the future has been cancelled, raises +CancelledError. If the future isn't done yet, raises +InvalidStateError. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_exception_impl(FutureObj *self) +/*[clinic end generated code: output=88b20d4f855e0710 input=733547a70c841c68]*/ +{ + if (self->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (self->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (self->fut_exception != NULL) { + self->fut_log_tb = 0; + Py_INCREF(self->fut_exception); + return self->fut_exception; + } + + Py_RETURN_NONE; +} + +/*[clinic input] +_asyncio.Future.set_result + + res: 'O' + / + +Mark the future done and set its result. + +If the future is already done when this method is called, raises +InvalidStateError. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_set_result(FutureObj *self, PyObject *res) +/*[clinic end generated code: output=a620abfc2796bfb6 input=8619565e0503357e]*/ +{ + return future_set_result(self, res); +} + +/*[clinic input] +_asyncio.Future.set_exception + + exception: 'O' + / + +Mark the future done and set an exception. + +If the future is already done when this method is called, raises +InvalidStateError. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_set_exception(FutureObj *self, PyObject *exception) +/*[clinic end generated code: output=f1c1b0cd321be360 input=1377dbe15e6ea186]*/ +{ + return future_set_exception(self, exception); +} + +/*[clinic input] +_asyncio.Future.add_done_callback + + fn: 'O' + / + +Add a callback to be run when the future becomes done. + +The callback is called with a single argument - the future object. If +the future is already done when this is called, the callback is +scheduled with call_soon. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_add_done_callback(FutureObj *self, PyObject *fn) +/*[clinic end generated code: output=819e09629b2ec2b5 input=8cce187e32cec6a8]*/ +{ + return future_add_done_callback(self, fn); +} + +/*[clinic input] +_asyncio.Future.remove_done_callback + + fn: 'O' + / + +Remove all instances of a callback from the "call when done" list. + +Returns the number of callbacks removed. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn) +/*[clinic end generated code: output=5ab1fb52b24ef31f input=3fedb73e1409c31c]*/ { PyObject *newlist; Py_ssize_t len, i, j=0; - len = PyList_GET_SIZE(fut->fut_callbacks); + len = PyList_GET_SIZE(self->fut_callbacks); if (len == 0) { return PyLong_FromSsize_t(0); } @@ -350,9 +523,9 @@ for (i = 0; i < len; i++) { int ret; - PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i); - if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + if ((ret = PyObject_RichCompareBool(fn, item, Py_EQ)) < 0) { goto fail; } if (ret == 0) { @@ -365,7 +538,7 @@ if (PyList_SetSlice(newlist, j, len, NULL) < 0) { goto fail; } - if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) { goto fail; } Py_DECREF(newlist); @@ -376,35 +549,34 @@ return NULL; } -PyDoc_STRVAR(pydoc_cancel, - "Cancel the future and schedule callbacks.\n" - "\n" - "If the future is already done or cancelled, return False. Otherwise,\n" - "change the future's state to cancelled, schedule the callbacks and\n" - "return True." -); +/*[clinic input] +_asyncio.Future.cancel + +Cancel the future and schedule callbacks. + +If the future is already done or cancelled, return False. Otherwise, +change the future's state to cancelled, schedule the callbacks and +return True. +[clinic start generated code]*/ static PyObject * -FutureObj_cancel(FutureObj *fut, PyObject *arg) +_asyncio_Future_cancel_impl(FutureObj *self) +/*[clinic end generated code: output=e45b932ba8bd68a1 input=515709a127995109]*/ { - if (fut->fut_state != STATE_PENDING) { - Py_RETURN_FALSE; - } - fut->fut_state = STATE_CANCELLED; - - if (_schedule_callbacks(fut) == -1) { - return NULL; - } - - Py_RETURN_TRUE; + return future_cancel(self); } -PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); +/*[clinic input] +_asyncio.Future.cancelled + +Return True if the future was cancelled. +[clinic start generated code]*/ static PyObject * -FutureObj_cancelled(FutureObj *fut, PyObject *arg) +_asyncio_Future_cancelled_impl(FutureObj *self) +/*[clinic end generated code: output=145197ced586357d input=943ab8b7b7b17e45]*/ { - if (fut->fut_state == STATE_CANCELLED) { + if (self->fut_state == STATE_CANCELLED) { Py_RETURN_TRUE; } else { @@ -412,17 +584,20 @@ } } -PyDoc_STRVAR(pydoc_done, - "Return True if the future is done.\n" - "\n" - "Done means either that a result / exception are available, or that the\n" - "future was cancelled." -); +/*[clinic input] +_asyncio.Future.done + +Return True if the future is done. + +Done means either that a result / exception are available, or that the +future was cancelled. +[clinic start generated code]*/ static PyObject * -FutureObj_done(FutureObj *fut, PyObject *arg) +_asyncio_Future_done_impl(FutureObj *self) +/*[clinic end generated code: output=244c5ac351145096 input=28d7b23fdb65d2ac]*/ { - if (fut->fut_state == STATE_PENDING) { + if (self->fut_state == STATE_PENDING) { Py_RETURN_FALSE; } else { @@ -538,13 +713,31 @@ return ret; } -static PyObject* -FutureObj__repr_info(FutureObj *fut) +/*[clinic input] +_asyncio.Future._repr_info +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future__repr_info_impl(FutureObj *self) +/*[clinic end generated code: output=fa69e901bd176cfb input=f21504d8e2ae1ca2]*/ { - if (asyncio_repr_info_func == NULL) { - return PyList_New(0); + return PyObject_CallFunctionObjArgs( + asyncio_future_repr_info_func, self, NULL); +} + +/*[clinic input] +_asyncio.Future._schedule_callbacks +[clinic start generated code]*/ + +static PyObject * +_asyncio_Future__schedule_callbacks_impl(FutureObj *self) +/*[clinic end generated code: output=5e8958d89ea1c5dc input=4f5f295f263f4a88]*/ +{ + int ret = future_schedule_callbacks(self); + if (ret == -1) { + return NULL; } - return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); + Py_RETURN_NONE; } static PyObject * @@ -661,43 +854,39 @@ static PyAsyncMethods FutureType_as_async = { - (unaryfunc)new_future_iter, /* am_await */ + (unaryfunc)future_new_iter, /* am_await */ 0, /* am_aiter */ 0 /* am_anext */ }; static PyMethodDef FutureType_methods[] = { - {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, - {"add_done_callback", - (PyCFunction)FutureObj_add_done_callback, - METH_O, pydoc_add_done_callback}, - {"remove_done_callback", - (PyCFunction)FutureObj_remove_done_callback, - METH_O, pydoc_remove_done_callback}, - {"set_result", - (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, - {"set_exception", - (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, - {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, - {"cancelled", - (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, - {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, - {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, - {"exception", - (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + _ASYNCIO_FUTURE_RESULT_METHODDEF + _ASYNCIO_FUTURE_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_SET_RESULT_METHODDEF + _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_CANCEL_METHODDEF + _ASYNCIO_FUTURE_CANCELLED_METHODDEF + _ASYNCIO_FUTURE_DONE_METHODDEF + _ASYNCIO_FUTURE__REPR_INFO_METHODDEF + _ASYNCIO_FUTURE__SCHEDULE_CALLBACKS_METHODDEF {NULL, NULL} /* Sentinel */ }; +#define FUTURE_COMMON_GETSETLIST \ + {"_state", (getter)FutureObj_get_state, NULL, NULL}, \ + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \ + (setter)FutureObj_set_blocking, NULL}, \ + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, \ + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \ + {"_result", (getter)FutureObj_get_result, NULL, NULL}, \ + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \ + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, \ + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + static PyGetSetDef FutureType_getsetlist[] = { - {"_state", (getter)FutureObj_get_state, NULL, NULL}, - {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, - (setter)FutureObj_set_blocking, NULL}, - {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, - {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, - {"_result", (getter)FutureObj_get_result, NULL, NULL}, - {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, - {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, - {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + FUTURE_COMMON_GETSETLIST {NULL} /* Sentinel */ }; @@ -712,25 +901,46 @@ .tp_repr = (reprfunc)FutureObj_repr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, - .tp_doc = "Fast asyncio.Future implementation.", + .tp_doc = _asyncio_Future___init____doc__, .tp_traverse = (traverseproc)FutureObj_traverse, .tp_clear = (inquiry)FutureObj_clear, .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), - .tp_iter = (getiterfunc)new_future_iter, + .tp_iter = (getiterfunc)future_new_iter, .tp_methods = FutureType_methods, .tp_getset = FutureType_getsetlist, .tp_dictoffset = offsetof(FutureObj, dict), - .tp_init = (initproc)FutureObj_init, + .tp_init = (initproc)_asyncio_Future___init__, .tp_new = PyType_GenericNew, .tp_finalize = (destructor)FutureObj_finalize, }; +#define Future_CheckExact(obj) (Py_TYPE(obj) == &FutureType) + +static inline int +future_call_schedule_callbacks(FutureObj *fut) +{ + if (Future_CheckExact(fut)) { + return future_schedule_callbacks(fut); + } + else { + /* `fut` is a subclass of Future */ + PyObject *ret = _PyObject_CallMethodId( + (PyObject*)fut, &PyId__schedule_callbacks, NULL); + if (ret == NULL) { + return -1; + } + + Py_DECREF(ret); + return 0; + } +} + static void FutureObj_dealloc(PyObject *self) { FutureObj *fut = (FutureObj *)self; - if (Py_TYPE(fut) == &FutureType) { + if (Future_CheckExact(fut)) { /* When fut is subclass of Future, finalizer is called from * subtype_dealloc. */ @@ -744,7 +954,7 @@ PyObject_ClearWeakRefs(self); } - FutureObj_clear(fut); + (void)FutureObj_clear(fut); Py_TYPE(fut)->tp_free(fut); } @@ -759,7 +969,7 @@ static void FutureIter_dealloc(futureiterobject *it) { - _PyObject_GC_UNTRACK(it); + PyObject_GC_UnTrack(it); Py_XDECREF(it->future); PyObject_GC_Del(it); } @@ -785,7 +995,7 @@ return NULL; } - res = FutureObj_result(fut, NULL); + res = _asyncio_Future_result_impl(fut); if (res != NULL) { /* The result of the Future is not an exception. @@ -884,37 +1094,19 @@ static PyTypeObject FutureIterType = { PyVarObject_HEAD_INIT(0, 0) "_asyncio.FutureIter", - sizeof(futureiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)FutureIter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 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 */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)FutureIter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)FutureIter_iternext, /* tp_iternext */ - FutureIter_methods, /* tp_methods */ - 0, /* tp_members */ + .tp_basicsize = sizeof(futureiterobject), + .tp_itemsize = 0, + .tp_dealloc = (destructor)FutureIter_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)FutureIter_traverse, + .tp_iter = PyObject_SelfIter, + .tp_iternext = (iternextfunc)FutureIter_iternext, + .tp_methods = FutureIter_methods, }; static PyObject * -new_future_iter(PyObject *fut) +future_new_iter(PyObject *fut) { futureiterobject *it; @@ -932,69 +1124,1284 @@ return (PyObject*)it; } -/*********************** Module **************************/ + +/*********************** Task **************************/ + + +/*[clinic input] +class _asyncio.Task "TaskObj *" "&Task_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=719dcef0fcc03b37]*/ + +static int task_call_step_soon(TaskObj *, PyObject *); +static inline PyObject * task_call_wakeup(TaskObj *, PyObject *); +static inline PyObject * task_call_step(TaskObj *, PyObject *); +static PyObject * task_wakeup(TaskObj *, PyObject *); +static PyObject * task_step(TaskObj *, PyObject *); + +/* ----- Task._step wrapper */ static int -init_module(void) +TaskSendMethWrapper_clear(TaskSendMethWrapper *o) { - PyObject *module = NULL; + Py_CLEAR(o->sw_task); + Py_CLEAR(o->sw_arg); + return 0; +} - module = PyImport_ImportModule("traceback"); - if (module == NULL) { +static void +TaskSendMethWrapper_dealloc(TaskSendMethWrapper *o) +{ + PyObject_GC_UnTrack(o); + (void)TaskSendMethWrapper_clear(o); + Py_TYPE(o)->tp_free(o); +} + +static PyObject * +TaskSendMethWrapper_call(TaskSendMethWrapper *o, + PyObject *args, PyObject *kwds) +{ + return task_call_step(o->sw_task, o->sw_arg); +} + +static int +TaskSendMethWrapper_traverse(TaskSendMethWrapper *o, + visitproc visit, void *arg) +{ + Py_VISIT(o->sw_task); + Py_VISIT(o->sw_arg); + return 0; +} + +static PyObject * +TaskSendMethWrapper_get___self__(TaskSendMethWrapper *o) +{ + if (o->sw_task) { + Py_INCREF(o->sw_task); + return (PyObject*)o->sw_task; + } + Py_RETURN_NONE; +} + +static PyGetSetDef TaskSendMethWrapper_getsetlist[] = { + {"__self__", (getter)TaskSendMethWrapper_get___self__, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +PyTypeObject TaskSendMethWrapper_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "TaskSendMethWrapper", + .tp_basicsize = sizeof(TaskSendMethWrapper), + .tp_itemsize = 0, + .tp_getset = TaskSendMethWrapper_getsetlist, + .tp_dealloc = (destructor)TaskSendMethWrapper_dealloc, + .tp_call = (ternaryfunc)TaskSendMethWrapper_call, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)TaskSendMethWrapper_traverse, + .tp_clear = (inquiry)TaskSendMethWrapper_clear, +}; + +static PyObject * +TaskSendMethWrapper_new(TaskObj *task, PyObject *arg) +{ + TaskSendMethWrapper *o; + o = PyObject_GC_New(TaskSendMethWrapper, &TaskSendMethWrapper_Type); + if (o == NULL) { + return NULL; + } + + Py_INCREF(task); + o->sw_task = task; + + Py_XINCREF(arg); + o->sw_arg = arg; + + PyObject_GC_Track(o); + return (PyObject*) o; +} + +/* ----- Task._wakeup wrapper */ + +static PyObject * +TaskWakeupMethWrapper_call(TaskWakeupMethWrapper *o, + PyObject *args, PyObject *kwds) +{ + PyObject *fut; + + if (!PyArg_ParseTuple(args, "O|", &fut)) { + return NULL; + } + + return task_call_wakeup(o->ww_task, fut); +} + +static int +TaskWakeupMethWrapper_clear(TaskWakeupMethWrapper *o) +{ + Py_CLEAR(o->ww_task); + return 0; +} + +static int +TaskWakeupMethWrapper_traverse(TaskWakeupMethWrapper *o, + visitproc visit, void *arg) +{ + Py_VISIT(o->ww_task); + return 0; +} + +static void +TaskWakeupMethWrapper_dealloc(TaskWakeupMethWrapper *o) +{ + PyObject_GC_UnTrack(o); + (void)TaskWakeupMethWrapper_clear(o); + Py_TYPE(o)->tp_free(o); +} + +PyTypeObject TaskWakeupMethWrapper_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "TaskWakeupMethWrapper", + .tp_basicsize = sizeof(TaskWakeupMethWrapper), + .tp_itemsize = 0, + .tp_dealloc = (destructor)TaskWakeupMethWrapper_dealloc, + .tp_call = (ternaryfunc)TaskWakeupMethWrapper_call, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)TaskWakeupMethWrapper_traverse, + .tp_clear = (inquiry)TaskWakeupMethWrapper_clear, +}; + +static PyObject * +TaskWakeupMethWrapper_new(TaskObj *task) +{ + TaskWakeupMethWrapper *o; + o = PyObject_GC_New(TaskWakeupMethWrapper, &TaskWakeupMethWrapper_Type); + if (o == NULL) { + return NULL; + } + + Py_INCREF(task); + o->ww_task = task; + + PyObject_GC_Track(o); + return (PyObject*) o; +} + +/* ----- Task */ + +/*[clinic input] +_asyncio.Task.__init__ + + coro: 'O' + * + loop: 'O' = NULL + +A coroutine wrapped in a Future. +[clinic start generated code]*/ + +static int +_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop) +/*[clinic end generated code: output=9f24774c2287fc2f input=71d8d28c201a18cd]*/ +{ + PyObject *res; + _Py_IDENTIFIER(add); + + if (future_init((FutureObj*)self, loop)) { return -1; } - // new reference - traceback_extract_stack = PyObject_GetAttrString(module, "extract_stack"); - if (traceback_extract_stack == NULL) { - goto fail; + + self->task_fut_waiter = NULL; + self->task_must_cancel = 0; + self->task_log_destroy_pending = 1; + + Py_INCREF(coro); + self->task_coro = coro; + + if (task_call_step_soon(self, NULL)) { + return -1; } - Py_DECREF(module); - module = PyImport_ImportModule("asyncio.events"); - if (module == NULL) { - goto fail; + res = _PyObject_CallMethodId(all_tasks, &PyId_add, "O", self, NULL); + if (res == NULL) { + return -1; } - asyncio_get_event_loop = PyObject_GetAttrString(module, "get_event_loop"); - if (asyncio_get_event_loop == NULL) { - goto fail; + Py_DECREF(res); + + return 0; +} + +static int +TaskObj_clear(TaskObj *task) +{ + (void)FutureObj_clear((FutureObj*) task); + Py_CLEAR(task->task_coro); + Py_CLEAR(task->task_fut_waiter); + return 0; +} + +static int +TaskObj_traverse(TaskObj *task, visitproc visit, void *arg) +{ + Py_VISIT(task->task_coro); + Py_VISIT(task->task_fut_waiter); + (void)FutureObj_traverse((FutureObj*) task, visit, arg); + return 0; +} + +static PyObject * +TaskObj_get_log_destroy_pending(TaskObj *task) +{ + if (task->task_log_destroy_pending) { + Py_RETURN_TRUE; } - Py_DECREF(module); + else { + Py_RETURN_FALSE; + } +} - module = PyImport_ImportModule("asyncio.futures"); - if (module == NULL) { - goto fail; +static int +TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; } - asyncio_repr_info_func = PyObject_GetAttrString(module, - "_future_repr_info"); - if (asyncio_repr_info_func == NULL) { + task->task_log_destroy_pending = is_true; + return 0; +} + +static PyObject * +TaskObj_get_must_cancel(TaskObj *task) +{ + if (task->task_must_cancel) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +TaskObj_get_coro(TaskObj *task) +{ + if (task->task_coro) { + Py_INCREF(task->task_coro); + return task->task_coro; + } + + Py_RETURN_NONE; +} + +static PyObject * +TaskObj_get_fut_waiter(TaskObj *task) +{ + if (task->task_fut_waiter) { + Py_INCREF(task->task_fut_waiter); + return task->task_fut_waiter; + } + + Py_RETURN_NONE; +} + +/*[clinic input] + at classmethod +_asyncio.Task.current_task + + loop: 'O' = NULL + +Return the currently running task in an event loop or None. + +By default the current task for the current event loop is returned. + +None is returned when called not in the context of a Task. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop) +/*[clinic end generated code: output=99fbe7332c516e03 input=cd784537f02cf833]*/ +{ + PyObject *res; + + if (loop == NULL) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return NULL; + } + + res = PyDict_GetItem((PyObject*)current_tasks, loop); + Py_DECREF(loop); + } + else { + res = PyDict_GetItem((PyObject*)current_tasks, loop); + } + + if (res == NULL) { + Py_RETURN_NONE; + } + else { + Py_INCREF(res); + return res; + } +} + +static PyObject * +task_all_tasks(PyObject *loop) +{ + PyObject *task; + PyObject *task_loop; + PyObject *set; + PyObject *iter; + + assert(loop != NULL); + + set = PySet_New(NULL); + if (set == NULL) { + return NULL; + } + + iter = PyObject_GetIter(all_tasks); + if (iter == NULL) { goto fail; } - asyncio_InvalidStateError = PyObject_GetAttrString(module, - "InvalidStateError"); - if (asyncio_InvalidStateError == NULL) { + while ((task = PyIter_Next(iter))) { + task_loop = PyObject_GetAttrString(task, "_loop"); + if (task_loop == NULL) { + Py_DECREF(task); + goto fail; + } + if (task_loop == loop) { + if (PySet_Add(set, task) == -1) { + Py_DECREF(task_loop); + Py_DECREF(task); + goto fail; + } + } + Py_DECREF(task_loop); + Py_DECREF(task); + } + + Py_DECREF(iter); + return set; + +fail: + Py_XDECREF(set); + Py_XDECREF(iter); + return NULL; +} + +/*[clinic input] + at classmethod +_asyncio.Task.all_tasks + + loop: 'O' = NULL + +Return a set of all tasks for an event loop. + +By default all tasks for the current event loop are returned. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop) +/*[clinic end generated code: output=11f9b20749ccca5d input=cd64aa5f88bd5c49]*/ +{ + PyObject *res; + + if (loop == NULL) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return NULL; + } + + res = task_all_tasks(loop); + Py_DECREF(loop); + } + else { + res = task_all_tasks(loop); + } + + return res; +} + +/*[clinic input] +_asyncio.Task._repr_info +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task__repr_info_impl(TaskObj *self) +/*[clinic end generated code: output=6a490eb66d5ba34b input=3c6d051ed3ddec8b]*/ +{ + return PyObject_CallFunctionObjArgs( + asyncio_task_repr_info_func, self, NULL); +} + +/*[clinic input] +_asyncio.Task.cancel + +Request that this task cancel itself. + +This arranges for a CancelledError to be thrown into the +wrapped coroutine on the next cycle through the event loop. +The coroutine then has a chance to clean up or even deny +the request using try/except/finally. + +Unlike Future.cancel, this does not guarantee that the +task will be cancelled: the exception might be caught and +acted upon, delaying cancellation of the task or preventing +cancellation completely. The task may also return a value or +raise a different exception. + +Immediately after this method is called, Task.cancelled() will +not return True (unless the task was already cancelled). A +task will be marked as cancelled when the wrapped coroutine +terminates with a CancelledError exception (even if cancel() +was not called). +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_cancel_impl(TaskObj *self) +/*[clinic end generated code: output=6bfc0479da9d5757 input=13f9bf496695cb52]*/ +{ + if (self->task_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + + if (self->task_fut_waiter) { + PyObject *res; + int is_true; + + res = _PyObject_CallMethodId( + self->task_fut_waiter, &PyId_cancel, NULL); + if (res == NULL) { + return NULL; + } + + is_true = PyObject_IsTrue(res); + Py_DECREF(res); + if (is_true < 0) { + return NULL; + } + + if (is_true) { + Py_RETURN_TRUE; + } + } + + self->task_must_cancel = 1; + Py_RETURN_TRUE; +} + +/*[clinic input] +_asyncio.Task.get_stack + + * + limit: 'O' = None + +Return the list of stack frames for this task's coroutine. + +If the coroutine is not done, this returns the stack where it is +suspended. If the coroutine has completed successfully or was +cancelled, this returns an empty list. If the coroutine was +terminated by an exception, this returns the list of traceback +frames. + +The frames are always ordered from oldest to newest. + +The optional limit gives the maximum number of frames to +return; by default all available frames are returned. Its +meaning differs depending on whether a stack or a traceback is +returned: the newest frames of a stack are returned, but the +oldest frames of a traceback are returned. (This matches the +behavior of the traceback module.) + +For reasons beyond our control, only one stack frame is +returned for a suspended coroutine. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit) +/*[clinic end generated code: output=c9aeeeebd1e18118 input=b1920230a766d17a]*/ +{ + return PyObject_CallFunctionObjArgs( + asyncio_task_get_stack_func, self, limit, NULL); +} + +/*[clinic input] +_asyncio.Task.print_stack + + * + limit: 'O' = None + file: 'O' = None + +Print the stack or traceback for this task's coroutine. + +This produces output similar to that of the traceback module, +for the frames retrieved by get_stack(). The limit argument +is passed to get_stack(). The file argument is an I/O stream +to which the output is written; by default output is written +to sys.stderr. +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit, + PyObject *file) +/*[clinic end generated code: output=7339e10314cd3f4d input=19f1e99ab5400bc3]*/ +{ + return PyObject_CallFunctionObjArgs( + asyncio_task_print_stack_func, self, limit, file, NULL); +} + +/*[clinic input] +_asyncio.Task._step + + exc: 'O' = NULL +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task__step_impl(TaskObj *self, PyObject *exc) +/*[clinic end generated code: output=7ed23f0cefd5ae42 input=ada4b2324e5370af]*/ +{ + return task_step(self, exc == Py_None ? NULL : exc); +} + +/*[clinic input] +_asyncio.Task._wakeup + + fut: 'O' +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task__wakeup_impl(TaskObj *self, PyObject *fut) +/*[clinic end generated code: output=75cb341c760fd071 input=11ee4918a5bdbf21]*/ +{ + return task_wakeup(self, fut); +} + +static void +TaskObj_finalize(TaskObj *task) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(task); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(source_traceback); + + PyObject *message = NULL; + PyObject *context = NULL; + PyObject *func = NULL; + PyObject *res = NULL; + + PyObject *error_type, *error_value, *error_traceback; + + if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) { + goto done; + } + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + context = PyDict_New(); + if (context == NULL) { + goto finally; + } + + message = PyUnicode_FromString("Task was destroyed but it is pending!"); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_task, (PyObject*)task) < 0) + { + goto finally; + } + + if (task->task_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + task->task_source_tb) < 0) + { + goto finally; + } + } + + func = _PyObject_GetAttrId(task->task_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + +done: + FutureObj_finalize((FutureObj*)task); +} + +static void TaskObj_dealloc(PyObject *); /* Needs Task_CheckExact */ + +static PyMethodDef TaskType_methods[] = { + _ASYNCIO_FUTURE_RESULT_METHODDEF + _ASYNCIO_FUTURE_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_SET_RESULT_METHODDEF + _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF + _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF + _ASYNCIO_FUTURE_CANCELLED_METHODDEF + _ASYNCIO_FUTURE_DONE_METHODDEF + _ASYNCIO_TASK_CURRENT_TASK_METHODDEF + _ASYNCIO_TASK_ALL_TASKS_METHODDEF + _ASYNCIO_TASK_CANCEL_METHODDEF + _ASYNCIO_TASK_GET_STACK_METHODDEF + _ASYNCIO_TASK_PRINT_STACK_METHODDEF + _ASYNCIO_TASK__WAKEUP_METHODDEF + _ASYNCIO_TASK__STEP_METHODDEF + _ASYNCIO_TASK__REPR_INFO_METHODDEF + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef TaskType_getsetlist[] = { + FUTURE_COMMON_GETSETLIST + {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending, + (setter)TaskObj_set_log_destroy_pending, NULL}, + {"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL}, + {"_coro", (getter)TaskObj_get_coro, NULL, NULL}, + {"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject TaskType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.Task", + sizeof(TaskObj), /* tp_basicsize */ + .tp_base = &FutureType, + .tp_dealloc = TaskObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = _asyncio_Task___init____doc__, + .tp_traverse = (traverseproc)TaskObj_traverse, + .tp_clear = (inquiry)TaskObj_clear, + .tp_weaklistoffset = offsetof(TaskObj, task_weakreflist), + .tp_iter = (getiterfunc)future_new_iter, + .tp_methods = TaskType_methods, + .tp_getset = TaskType_getsetlist, + .tp_dictoffset = offsetof(TaskObj, dict), + .tp_init = (initproc)_asyncio_Task___init__, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)TaskObj_finalize, +}; + +#define Task_CheckExact(obj) (Py_TYPE(obj) == &TaskType) + +static void +TaskObj_dealloc(PyObject *self) +{ + TaskObj *task = (TaskObj *)self; + + if (Task_CheckExact(self)) { + /* When fut is subclass of Task, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (task->task_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + (void)TaskObj_clear(task); + Py_TYPE(task)->tp_free(task); +} + +static inline PyObject * +task_call_wakeup(TaskObj *task, PyObject *fut) +{ + if (Task_CheckExact(task)) { + return task_wakeup(task, fut); + } + else { + /* `task` is a subclass of Task */ + return _PyObject_CallMethodId( + (PyObject*)task, &PyId__wakeup, "O", fut, NULL); + } +} + +static inline PyObject * +task_call_step(TaskObj *task, PyObject *arg) +{ + if (Task_CheckExact(task)) { + return task_step(task, arg); + } + else { + /* `task` is a subclass of Task */ + if (arg == NULL) { + arg = Py_None; + } + return _PyObject_CallMethodId( + (PyObject*)task, &PyId__step, "O", arg, NULL); + } +} + +static int +task_call_step_soon(TaskObj *task, PyObject *arg) +{ + PyObject *handle; + + PyObject *cb = TaskSendMethWrapper_new(task, arg); + if (cb == NULL) { + return -1; + } + + handle = _PyObject_CallMethodId( + task->task_loop, &PyId_call_soon, "O", cb, NULL); + Py_DECREF(cb); + if (handle == NULL) { + return -1; + } + + Py_DECREF(handle); + return 0; +} + +static PyObject * +task_set_error_soon(TaskObj *task, PyObject *et, const char *format, ...) +{ + PyObject* msg; + + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + msg = PyUnicode_FromFormatV(format, vargs); + va_end(vargs); + + if (msg == NULL) { + return NULL; + } + + PyObject *e = PyObject_CallFunctionObjArgs(et, msg, NULL); + Py_DECREF(msg); + if (e == NULL) { + return NULL; + } + + if (task_call_step_soon(task, e) == -1) { + Py_DECREF(e); + return NULL; + } + + Py_DECREF(e); + Py_RETURN_NONE; +} + +static PyObject * +task_step_impl(TaskObj *task, PyObject *exc) +{ + int res; + int clear_exc = 0; + PyObject *result = NULL; + PyObject *coro = task->task_coro; + PyObject *o; + + if (task->task_state != STATE_PENDING) { + PyErr_Format(PyExc_AssertionError, + "_step(): already done: %R %R", + task, + exc ? exc : Py_None); goto fail; } - asyncio_CancelledError = PyObject_GetAttrString(module, "CancelledError"); - if (asyncio_CancelledError == NULL) { + if (task->task_must_cancel) { + assert(exc != Py_None); + + if (exc) { + /* Check if exc is a CancelledError */ + res = PyObject_IsInstance(exc, asyncio_CancelledError); + if (res == -1) { + /* An error occurred, abort */ + goto fail; + } + if (res == 0) { + /* exc is not CancelledError; reset it to NULL */ + exc = NULL; + } + } + + if (!exc) { + /* exc was not a CancelledError */ + exc = PyObject_CallFunctionObjArgs(asyncio_CancelledError, NULL); + if (!exc) { + goto fail; + } + clear_exc = 1; + } + + task->task_must_cancel = 0; + } + + Py_CLEAR(task->task_fut_waiter); + + if (exc == NULL) { + if (PyGen_CheckExact(coro) || PyCoro_CheckExact(coro)) { + result = _PyGen_Send((PyGenObject*)coro, Py_None); + } + else { + result = _PyObject_CallMethodIdObjArgs( + coro, &PyId_send, Py_None, NULL); + } + } + else { + result = _PyObject_CallMethodIdObjArgs( + coro, &PyId_throw, exc, NULL); + if (clear_exc) { + /* We created 'exc' during this call */ + Py_CLEAR(exc); + } + } + + if (result == NULL) { + PyObject *et, *ev, *tb; + + if (_PyGen_FetchStopIterationValue(&o) == 0) { + /* The error is StopIteration and that means that + the underlying coroutine has resolved */ + PyObject *res = future_set_result((FutureObj*)task, o); + Py_DECREF(o); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + Py_RETURN_NONE; + } + + if (PyErr_ExceptionMatches(asyncio_CancelledError)) { + /* CancelledError */ + PyErr_Clear(); + return future_cancel((FutureObj*)task); + } + + /* Some other exception; pop it and call Task.set_exception() */ + PyErr_Fetch(&et, &ev, &tb); + assert(et); + if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { + PyErr_NormalizeException(&et, &ev, &tb); + } + o = future_set_exception((FutureObj*)task, ev); + if (!o) { + /* An exception in Task.set_exception() */ + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + goto fail; + } + assert(o == Py_None); + Py_CLEAR(o); + + if (!PyErr_GivenExceptionMatches(et, PyExc_Exception)) { + /* We've got a BaseException; re-raise it */ + PyErr_Restore(et, ev, tb); + goto fail; + } + + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + + Py_RETURN_NONE; + } + + if (result == (PyObject*)task) { + /* We have a task that wants to await on itself */ + goto self_await; + } + + /* Check if `result` is FutureObj or TaskObj (and not a subclass) */ + if (Future_CheckExact(result) || Task_CheckExact(result)) { + PyObject *wrapper; + PyObject *res; + FutureObj *fut = (FutureObj*)result; + + /* Check if `result` future is attached to a different loop */ + if (fut->fut_loop != task->task_loop) { + goto different_loop; + } + + if (fut->fut_blocking) { + fut->fut_blocking = 0; + + /* result.add_done_callback(task._wakeup) */ + wrapper = TaskWakeupMethWrapper_new(task); + if (wrapper == NULL) { + goto fail; + } + res = future_add_done_callback((FutureObj*)result, wrapper); + Py_DECREF(wrapper); + if (res == NULL) { + goto fail; + } + Py_DECREF(res); + + /* task._fut_waiter = result */ + task->task_fut_waiter = result; /* no incref is necessary */ + + if (task->task_must_cancel) { + PyObject *r; + r = future_cancel(fut); + if (r == NULL) { + return NULL; + } + if (r == Py_True) { + task->task_must_cancel = 0; + } + Py_DECREF(r); + } + + Py_RETURN_NONE; + } + else { + goto yield_insteadof_yf; + } + } + + /* Check if `result` is a Future-compatible object */ + o = PyObject_GetAttrString(result, "_asyncio_future_blocking"); + if (o == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } + else { + goto fail; + } + } + else { + if (o == Py_None) { + Py_CLEAR(o); + } + else { + /* `result` is a Future-compatible object */ + PyObject *wrapper; + PyObject *res; + + int blocking = PyObject_IsTrue(o); + Py_CLEAR(o); + if (blocking < 0) { + goto fail; + } + + /* Check if `result` future is attached to a different loop */ + PyObject *oloop = PyObject_GetAttrString(result, "_loop"); + if (oloop == NULL) { + goto fail; + } + if (oloop != task->task_loop) { + Py_DECREF(oloop); + goto different_loop; + } + else { + Py_DECREF(oloop); + } + + if (blocking) { + /* result._asyncio_future_blocking = False */ + if (PyObject_SetAttrString( + result, "_asyncio_future_blocking", Py_False) == -1) { + goto fail; + } + + /* result.add_done_callback(task._wakeup) */ + wrapper = TaskWakeupMethWrapper_new(task); + if (wrapper == NULL) { + goto fail; + } + res = _PyObject_CallMethodId( + result, &PyId_add_done_callback, "O", wrapper, NULL); + Py_DECREF(wrapper); + if (res == NULL) { + goto fail; + } + Py_DECREF(res); + + /* task._fut_waiter = result */ + task->task_fut_waiter = result; /* no incref is necessary */ + + if (task->task_must_cancel) { + PyObject *r; + int is_true; + r = _PyObject_CallMethodId(result, &PyId_cancel, NULL); + if (r == NULL) { + return NULL; + } + is_true = PyObject_IsTrue(r); + Py_DECREF(r); + if (is_true < 0) { + return NULL; + } + else if (is_true) { + task->task_must_cancel = 0; + } + } + + Py_RETURN_NONE; + } + else { + goto yield_insteadof_yf; + } + } + } + + /* Check if `result` is None */ + if (result == Py_None) { + /* Bare yield relinquishes control for one event loop iteration. */ + if (task_call_step_soon(task, NULL)) { + goto fail; + } + return result; + } + + /* Check if `result` is a generator */ + o = PyObject_CallFunctionObjArgs(inspect_isgenerator, result, NULL); + if (o == NULL) { + /* An exception in inspect.isgenerator */ + goto fail; + } + res = PyObject_IsTrue(o); + Py_CLEAR(o); + if (res == -1) { + /* An exception while checking if 'val' is True */ + goto fail; + } + if (res == 1) { + /* `result` is a generator */ + PyObject *ret; + ret = task_set_error_soon( + task, PyExc_RuntimeError, + "yield was used instead of yield from for " + "generator in task %R with %S", task, result); + Py_DECREF(result); + return ret; + } + + /* The `result` is none of the above */ + Py_DECREF(result); + return task_set_error_soon( + task, PyExc_RuntimeError, "Task got bad yield: %R", result); + +self_await: + o = task_set_error_soon( + task, PyExc_RuntimeError, + "Task cannot await on itself: %R", task); + Py_DECREF(result); + return o; + +yield_insteadof_yf: + o = task_set_error_soon( + task, PyExc_RuntimeError, + "yield was used instead of yield from " + "in task %R with %R", + task, result); + Py_DECREF(result); + return o; + +different_loop: + o = task_set_error_soon( + task, PyExc_RuntimeError, + "Task %R got Future %R attached to a different loop", + task, result); + Py_DECREF(result); + return o; + +fail: + Py_XDECREF(result); + return NULL; +} + +static PyObject * +task_step(TaskObj *task, PyObject *exc) +{ + PyObject *res; + PyObject *ot; + + if (PyDict_SetItem((PyObject *)current_tasks, + task->task_loop, (PyObject*)task) == -1) + { + return NULL; + } + + res = task_step_impl(task, exc); + + if (res == NULL) { + PyObject *et, *ev, *tb; + PyErr_Fetch(&et, &ev, &tb); + ot = _PyDict_Pop(current_tasks, task->task_loop, NULL); + if (ot == NULL) { + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + return NULL; + } + Py_DECREF(ot); + PyErr_Restore(et, ev, tb); + return NULL; + } + else { + ot = _PyDict_Pop(current_tasks, task->task_loop, NULL); + if (ot == NULL) { + Py_DECREF(res); + return NULL; + } + else { + Py_DECREF(ot); + return res; + } + } +} + +static PyObject * +task_wakeup(TaskObj *task, PyObject *o) +{ + assert(o); + + if (Future_CheckExact(o) || Task_CheckExact(o)) { + PyObject *fut_result = NULL; + int res = future_get_result((FutureObj*)o, &fut_result); + PyObject *result; + + switch(res) { + case -1: + assert(fut_result == NULL); + return NULL; + case 0: + Py_DECREF(fut_result); + return task_call_step(task, NULL); + default: + assert(res == 1); + result = task_call_step(task, fut_result); + Py_DECREF(fut_result); + return result; + } + } + + PyObject *fut_result = PyObject_CallMethod(o, "result", NULL); + if (fut_result == NULL) { + PyObject *et, *ev, *tb; + PyObject *res; + + PyErr_Fetch(&et, &ev, &tb); + if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { + PyErr_NormalizeException(&et, &ev, &tb); + } + + res = task_call_step(task, ev); + + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + + return res; + } + else { + Py_DECREF(fut_result); + return task_call_step(task, NULL); + } +} + + +/*********************** Module **************************/ + + +static void +module_free(void *m) +{ + Py_CLEAR(current_tasks); + Py_CLEAR(all_tasks); + Py_CLEAR(traceback_extract_stack); + Py_CLEAR(asyncio_get_event_loop); + Py_CLEAR(asyncio_future_repr_info_func); + Py_CLEAR(asyncio_task_repr_info_func); + Py_CLEAR(asyncio_task_get_stack_func); + Py_CLEAR(asyncio_task_print_stack_func); + Py_CLEAR(asyncio_InvalidStateError); + Py_CLEAR(asyncio_CancelledError); + Py_CLEAR(inspect_isgenerator); +} + +static int +module_init(void) +{ + PyObject *module = NULL; + PyObject *cls; + +#define WITH_MOD(NAME) \ + Py_CLEAR(module); \ + module = PyImport_ImportModule(NAME); \ + if (module == NULL) { \ + return -1; \ + } + +#define GET_MOD_ATTR(VAR, NAME) \ + VAR = PyObject_GetAttrString(module, NAME); \ + if (VAR == NULL) { \ + goto fail; \ + } + + WITH_MOD("asyncio.events") + GET_MOD_ATTR(asyncio_get_event_loop, "get_event_loop") + + WITH_MOD("asyncio.base_futures") + GET_MOD_ATTR(asyncio_future_repr_info_func, "_future_repr_info") + GET_MOD_ATTR(asyncio_InvalidStateError, "InvalidStateError") + GET_MOD_ATTR(asyncio_CancelledError, "CancelledError") + + WITH_MOD("asyncio.base_tasks") + GET_MOD_ATTR(asyncio_task_repr_info_func, "_task_repr_info") + GET_MOD_ATTR(asyncio_task_get_stack_func, "_task_get_stack") + GET_MOD_ATTR(asyncio_task_print_stack_func, "_task_print_stack") + + WITH_MOD("inspect") + GET_MOD_ATTR(inspect_isgenerator, "isgenerator") + + WITH_MOD("traceback") + GET_MOD_ATTR(traceback_extract_stack, "extract_stack") + + WITH_MOD("weakref") + GET_MOD_ATTR(cls, "WeakSet") + all_tasks = PyObject_CallObject(cls, NULL); + Py_CLEAR(cls); + if (all_tasks == NULL) { goto fail; } - Py_DECREF(module); + current_tasks = (PyDictObject *)PyDict_New(); + if (current_tasks == NULL) { + goto fail; + } + + Py_CLEAR(module); return 0; fail: - Py_CLEAR(traceback_extract_stack); - Py_CLEAR(asyncio_get_event_loop); - Py_CLEAR(asyncio_repr_info_func); - Py_CLEAR(asyncio_InvalidStateError); - Py_CLEAR(asyncio_CancelledError); Py_CLEAR(module); + module_free(NULL); return -1; + +#undef WITH_MOD +#undef GET_MOD_ATTR } - PyDoc_STRVAR(module_doc, "Accelerator module for asyncio"); static struct PyModuleDef _asynciomodule = { @@ -1006,14 +2413,14 @@ NULL, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ - NULL, /* m_free */ + (freefunc)module_free /* m_free */ }; PyMODINIT_FUNC PyInit__asyncio(void) { - if (init_module() < 0) { + if (module_init() < 0) { return NULL; } if (PyType_Ready(&FutureType) < 0) { @@ -1022,6 +2429,15 @@ if (PyType_Ready(&FutureIterType) < 0) { return NULL; } + if (PyType_Ready(&TaskSendMethWrapper_Type) < 0) { + return NULL; + } + if(PyType_Ready(&TaskWakeupMethWrapper_Type) < 0) { + return NULL; + } + if (PyType_Ready(&TaskType) < 0) { + return NULL; + } PyObject *m = PyModule_Create(&_asynciomodule); if (m == NULL) { @@ -1034,5 +2450,11 @@ return NULL; } + Py_INCREF(&TaskType); + if (PyModule_AddObject(m, "Task", (PyObject *)&TaskType) < 0) { + Py_DECREF(&TaskType); + return NULL; + } + return m; } diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/_asynciomodule.c.h @@ -0,0 +1,520 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_asyncio_Future___init____doc__, +"Future(*, loop=None)\n" +"--\n" +"\n" +"This class is *almost* compatible with concurrent.futures.Future.\n" +"\n" +" Differences:\n" +"\n" +" - result() and exception() do not take a timeout argument and\n" +" raise an exception when the future isn\'t done yet.\n" +"\n" +" - Callbacks registered with add_done_callback() are always called\n" +" via the event loop\'s call_soon_threadsafe().\n" +"\n" +" - This class is not compatible with the wait() and as_completed()\n" +" methods in the concurrent.futures package."); + +static int +_asyncio_Future___init___impl(FutureObj *self, PyObject *loop); + +static int +_asyncio_Future___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"loop", NULL}; + static _PyArg_Parser _parser = {"|$O:Future", _keywords, 0}; + PyObject *loop = NULL; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &loop)) { + goto exit; + } + return_value = _asyncio_Future___init___impl((FutureObj *)self, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Future_result__doc__, +"result($self, /)\n" +"--\n" +"\n" +"Return the result this future represents.\n" +"\n" +"If the future has been cancelled, raises CancelledError. If the\n" +"future\'s result isn\'t yet available, raises InvalidStateError. If\n" +"the future is done and has an exception set, this exception is raised."); + +#define _ASYNCIO_FUTURE_RESULT_METHODDEF \ + {"result", (PyCFunction)_asyncio_Future_result, METH_NOARGS, _asyncio_Future_result__doc__}, + +static PyObject * +_asyncio_Future_result_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_result(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_result_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_exception__doc__, +"exception($self, /)\n" +"--\n" +"\n" +"Return the exception that was set on this future.\n" +"\n" +"The exception (or None if no exception was set) is returned only if\n" +"the future is done. If the future has been cancelled, raises\n" +"CancelledError. If the future isn\'t done yet, raises\n" +"InvalidStateError."); + +#define _ASYNCIO_FUTURE_EXCEPTION_METHODDEF \ + {"exception", (PyCFunction)_asyncio_Future_exception, METH_NOARGS, _asyncio_Future_exception__doc__}, + +static PyObject * +_asyncio_Future_exception_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_exception(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_exception_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_set_result__doc__, +"set_result($self, res, /)\n" +"--\n" +"\n" +"Mark the future done and set its result.\n" +"\n" +"If the future is already done when this method is called, raises\n" +"InvalidStateError."); + +#define _ASYNCIO_FUTURE_SET_RESULT_METHODDEF \ + {"set_result", (PyCFunction)_asyncio_Future_set_result, METH_O, _asyncio_Future_set_result__doc__}, + +PyDoc_STRVAR(_asyncio_Future_set_exception__doc__, +"set_exception($self, exception, /)\n" +"--\n" +"\n" +"Mark the future done and set an exception.\n" +"\n" +"If the future is already done when this method is called, raises\n" +"InvalidStateError."); + +#define _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF \ + {"set_exception", (PyCFunction)_asyncio_Future_set_exception, METH_O, _asyncio_Future_set_exception__doc__}, + +PyDoc_STRVAR(_asyncio_Future_add_done_callback__doc__, +"add_done_callback($self, fn, /)\n" +"--\n" +"\n" +"Add a callback to be run when the future becomes done.\n" +"\n" +"The callback is called with a single argument - the future object. If\n" +"the future is already done when this is called, the callback is\n" +"scheduled with call_soon."); + +#define _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF \ + {"add_done_callback", (PyCFunction)_asyncio_Future_add_done_callback, METH_O, _asyncio_Future_add_done_callback__doc__}, + +PyDoc_STRVAR(_asyncio_Future_remove_done_callback__doc__, +"remove_done_callback($self, fn, /)\n" +"--\n" +"\n" +"Remove all instances of a callback from the \"call when done\" list.\n" +"\n" +"Returns the number of callbacks removed."); + +#define _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF \ + {"remove_done_callback", (PyCFunction)_asyncio_Future_remove_done_callback, METH_O, _asyncio_Future_remove_done_callback__doc__}, + +PyDoc_STRVAR(_asyncio_Future_cancel__doc__, +"cancel($self, /)\n" +"--\n" +"\n" +"Cancel the future and schedule callbacks.\n" +"\n" +"If the future is already done or cancelled, return False. Otherwise,\n" +"change the future\'s state to cancelled, schedule the callbacks and\n" +"return True."); + +#define _ASYNCIO_FUTURE_CANCEL_METHODDEF \ + {"cancel", (PyCFunction)_asyncio_Future_cancel, METH_NOARGS, _asyncio_Future_cancel__doc__}, + +static PyObject * +_asyncio_Future_cancel_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_cancel(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_cancel_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_cancelled__doc__, +"cancelled($self, /)\n" +"--\n" +"\n" +"Return True if the future was cancelled."); + +#define _ASYNCIO_FUTURE_CANCELLED_METHODDEF \ + {"cancelled", (PyCFunction)_asyncio_Future_cancelled, METH_NOARGS, _asyncio_Future_cancelled__doc__}, + +static PyObject * +_asyncio_Future_cancelled_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_cancelled(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_cancelled_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future_done__doc__, +"done($self, /)\n" +"--\n" +"\n" +"Return True if the future is done.\n" +"\n" +"Done means either that a result / exception are available, or that the\n" +"future was cancelled."); + +#define _ASYNCIO_FUTURE_DONE_METHODDEF \ + {"done", (PyCFunction)_asyncio_Future_done, METH_NOARGS, _asyncio_Future_done__doc__}, + +static PyObject * +_asyncio_Future_done_impl(FutureObj *self); + +static PyObject * +_asyncio_Future_done(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future_done_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future__repr_info__doc__, +"_repr_info($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_FUTURE__REPR_INFO_METHODDEF \ + {"_repr_info", (PyCFunction)_asyncio_Future__repr_info, METH_NOARGS, _asyncio_Future__repr_info__doc__}, + +static PyObject * +_asyncio_Future__repr_info_impl(FutureObj *self); + +static PyObject * +_asyncio_Future__repr_info(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future__repr_info_impl(self); +} + +PyDoc_STRVAR(_asyncio_Future__schedule_callbacks__doc__, +"_schedule_callbacks($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_FUTURE__SCHEDULE_CALLBACKS_METHODDEF \ + {"_schedule_callbacks", (PyCFunction)_asyncio_Future__schedule_callbacks, METH_NOARGS, _asyncio_Future__schedule_callbacks__doc__}, + +static PyObject * +_asyncio_Future__schedule_callbacks_impl(FutureObj *self); + +static PyObject * +_asyncio_Future__schedule_callbacks(FutureObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Future__schedule_callbacks_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task___init____doc__, +"Task(coro, *, loop=None)\n" +"--\n" +"\n" +"A coroutine wrapped in a Future."); + +static int +_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop); + +static int +_asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"coro", "loop", NULL}; + static _PyArg_Parser _parser = {"O|$O:Task", _keywords, 0}; + PyObject *coro; + PyObject *loop = NULL; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &coro, &loop)) { + goto exit; + } + return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task_current_task__doc__, +"current_task($type, /, loop=None)\n" +"--\n" +"\n" +"Return the currently running task in an event loop or None.\n" +"\n" +"By default the current task for the current event loop is returned.\n" +"\n" +"None is returned when called not in the context of a Task."); + +#define _ASYNCIO_TASK_CURRENT_TASK_METHODDEF \ + {"current_task", (PyCFunction)_asyncio_Task_current_task, METH_FASTCALL|METH_CLASS, _asyncio_Task_current_task__doc__}, + +static PyObject * +_asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop); + +static PyObject * +_asyncio_Task_current_task(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"loop", NULL}; + static _PyArg_Parser _parser = {"|O:current_task", _keywords, 0}; + PyObject *loop = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &loop)) { + goto exit; + } + return_value = _asyncio_Task_current_task_impl(type, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task_all_tasks__doc__, +"all_tasks($type, /, loop=None)\n" +"--\n" +"\n" +"Return a set of all tasks for an event loop.\n" +"\n" +"By default all tasks for the current event loop are returned."); + +#define _ASYNCIO_TASK_ALL_TASKS_METHODDEF \ + {"all_tasks", (PyCFunction)_asyncio_Task_all_tasks, METH_FASTCALL|METH_CLASS, _asyncio_Task_all_tasks__doc__}, + +static PyObject * +_asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop); + +static PyObject * +_asyncio_Task_all_tasks(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"loop", NULL}; + static _PyArg_Parser _parser = {"|O:all_tasks", _keywords, 0}; + PyObject *loop = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &loop)) { + goto exit; + } + return_value = _asyncio_Task_all_tasks_impl(type, loop); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task__repr_info__doc__, +"_repr_info($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK__REPR_INFO_METHODDEF \ + {"_repr_info", (PyCFunction)_asyncio_Task__repr_info, METH_NOARGS, _asyncio_Task__repr_info__doc__}, + +static PyObject * +_asyncio_Task__repr_info_impl(TaskObj *self); + +static PyObject * +_asyncio_Task__repr_info(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task__repr_info_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task_cancel__doc__, +"cancel($self, /)\n" +"--\n" +"\n" +"Request that this task cancel itself.\n" +"\n" +"This arranges for a CancelledError to be thrown into the\n" +"wrapped coroutine on the next cycle through the event loop.\n" +"The coroutine then has a chance to clean up or even deny\n" +"the request using try/except/finally.\n" +"\n" +"Unlike Future.cancel, this does not guarantee that the\n" +"task will be cancelled: the exception might be caught and\n" +"acted upon, delaying cancellation of the task or preventing\n" +"cancellation completely. The task may also return a value or\n" +"raise a different exception.\n" +"\n" +"Immediately after this method is called, Task.cancelled() will\n" +"not return True (unless the task was already cancelled). A\n" +"task will be marked as cancelled when the wrapped coroutine\n" +"terminates with a CancelledError exception (even if cancel()\n" +"was not called)."); + +#define _ASYNCIO_TASK_CANCEL_METHODDEF \ + {"cancel", (PyCFunction)_asyncio_Task_cancel, METH_NOARGS, _asyncio_Task_cancel__doc__}, + +static PyObject * +_asyncio_Task_cancel_impl(TaskObj *self); + +static PyObject * +_asyncio_Task_cancel(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task_cancel_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task_get_stack__doc__, +"get_stack($self, /, *, limit=None)\n" +"--\n" +"\n" +"Return the list of stack frames for this task\'s coroutine.\n" +"\n" +"If the coroutine is not done, this returns the stack where it is\n" +"suspended. If the coroutine has completed successfully or was\n" +"cancelled, this returns an empty list. If the coroutine was\n" +"terminated by an exception, this returns the list of traceback\n" +"frames.\n" +"\n" +"The frames are always ordered from oldest to newest.\n" +"\n" +"The optional limit gives the maximum number of frames to\n" +"return; by default all available frames are returned. Its\n" +"meaning differs depending on whether a stack or a traceback is\n" +"returned: the newest frames of a stack are returned, but the\n" +"oldest frames of a traceback are returned. (This matches the\n" +"behavior of the traceback module.)\n" +"\n" +"For reasons beyond our control, only one stack frame is\n" +"returned for a suspended coroutine."); + +#define _ASYNCIO_TASK_GET_STACK_METHODDEF \ + {"get_stack", (PyCFunction)_asyncio_Task_get_stack, METH_FASTCALL, _asyncio_Task_get_stack__doc__}, + +static PyObject * +_asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit); + +static PyObject * +_asyncio_Task_get_stack(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"limit", NULL}; + static _PyArg_Parser _parser = {"|$O:get_stack", _keywords, 0}; + PyObject *limit = Py_None; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &limit)) { + goto exit; + } + return_value = _asyncio_Task_get_stack_impl(self, limit); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task_print_stack__doc__, +"print_stack($self, /, *, limit=None, file=None)\n" +"--\n" +"\n" +"Print the stack or traceback for this task\'s coroutine.\n" +"\n" +"This produces output similar to that of the traceback module,\n" +"for the frames retrieved by get_stack(). The limit argument\n" +"is passed to get_stack(). The file argument is an I/O stream\n" +"to which the output is written; by default output is written\n" +"to sys.stderr."); + +#define _ASYNCIO_TASK_PRINT_STACK_METHODDEF \ + {"print_stack", (PyCFunction)_asyncio_Task_print_stack, METH_FASTCALL, _asyncio_Task_print_stack__doc__}, + +static PyObject * +_asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit, + PyObject *file); + +static PyObject * +_asyncio_Task_print_stack(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"limit", "file", NULL}; + static _PyArg_Parser _parser = {"|$OO:print_stack", _keywords, 0}; + PyObject *limit = Py_None; + PyObject *file = Py_None; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &limit, &file)) { + goto exit; + } + return_value = _asyncio_Task_print_stack_impl(self, limit, file); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task__step__doc__, +"_step($self, /, exc=None)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK__STEP_METHODDEF \ + {"_step", (PyCFunction)_asyncio_Task__step, METH_FASTCALL, _asyncio_Task__step__doc__}, + +static PyObject * +_asyncio_Task__step_impl(TaskObj *self, PyObject *exc); + +static PyObject * +_asyncio_Task__step(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"exc", NULL}; + static _PyArg_Parser _parser = {"|O:_step", _keywords, 0}; + PyObject *exc = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &exc)) { + goto exit; + } + return_value = _asyncio_Task__step_impl(self, exc); + +exit: + return return_value; +} + +PyDoc_STRVAR(_asyncio_Task__wakeup__doc__, +"_wakeup($self, /, fut)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK__WAKEUP_METHODDEF \ + {"_wakeup", (PyCFunction)_asyncio_Task__wakeup, METH_FASTCALL, _asyncio_Task__wakeup__doc__}, + +static PyObject * +_asyncio_Task__wakeup_impl(TaskObj *self, PyObject *fut); + +static PyObject * +_asyncio_Task__wakeup(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"fut", NULL}; + static _PyArg_Parser _parser = {"O:_wakeup", _keywords, 0}; + PyObject *fut; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &fut)) { + goto exit; + } + return_value = _asyncio_Task__wakeup_impl(self, fut); + +exit: + return return_value; +} +/*[clinic end generated code: output=8f036321bb083066 input=a9049054013a1b77]*/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 13:17:23 2016 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Oct 2016 17:17:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42?= Message-ID: <20161028171719.21936.93957.BF187737@psf.io> https://hg.python.org/cpython/rev/245ee609feea changeset: 104778:245ee609feea parent: 104776:8059289b55c1 parent: 104777:fb7c439103b9 user: Victor Stinner date: Fri Oct 28 19:15:08 2016 +0200 summary: Merge 3.6 files: Modules/_asynciomodule.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -893,7 +893,7 @@ static void FutureObj_dealloc(PyObject *self); static PyTypeObject FutureType = { - PyVarObject_HEAD_INIT(0, 0) + PyVarObject_HEAD_INIT(NULL, 0) "_asyncio.Future", sizeof(FutureObj), /* tp_basicsize */ .tp_dealloc = FutureObj_dealloc, @@ -1092,7 +1092,7 @@ }; static PyTypeObject FutureIterType = { - PyVarObject_HEAD_INIT(0, 0) + PyVarObject_HEAD_INIT(NULL, 0) "_asyncio.FutureIter", .tp_basicsize = sizeof(futureiterobject), .tp_itemsize = 0, @@ -1189,7 +1189,7 @@ }; PyTypeObject TaskSendMethWrapper_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(NULL, 0) "TaskSendMethWrapper", .tp_basicsize = sizeof(TaskSendMethWrapper), .tp_itemsize = 0, @@ -1260,7 +1260,7 @@ } PyTypeObject TaskWakeupMethWrapper_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(NULL, 0) "TaskWakeupMethWrapper", .tp_basicsize = sizeof(TaskWakeupMethWrapper), .tp_itemsize = 0, @@ -1778,7 +1778,7 @@ }; static PyTypeObject TaskType = { - PyVarObject_HEAD_INIT(0, 0) + PyVarObject_HEAD_INIT(NULL, 0) "_asyncio.Task", sizeof(TaskObj), /* tp_basicsize */ .tp_base = &FutureType, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 13:17:23 2016 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Oct 2016 17:17:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTQ0?= =?utf-8?q?=3A_Fix_=5Fasynciomodule=2Ec_on_Windows?= Message-ID: <20161028171719.32321.31207.F24E66BF@psf.io> https://hg.python.org/cpython/rev/fb7c439103b9 changeset: 104777:fb7c439103b9 branch: 3.6 parent: 104775:db5ae4f6df8a user: Victor Stinner date: Fri Oct 28 19:13:52 2016 +0200 summary: Issue #28544: Fix _asynciomodule.c on Windows PyType_Ready() sets the reference to &PyType_Type. &PyType_Type cannot be resolved at compilation time (not on Windows?). files: Modules/_asynciomodule.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -893,7 +893,7 @@ static void FutureObj_dealloc(PyObject *self); static PyTypeObject FutureType = { - PyVarObject_HEAD_INIT(0, 0) + PyVarObject_HEAD_INIT(NULL, 0) "_asyncio.Future", sizeof(FutureObj), /* tp_basicsize */ .tp_dealloc = FutureObj_dealloc, @@ -1092,7 +1092,7 @@ }; static PyTypeObject FutureIterType = { - PyVarObject_HEAD_INIT(0, 0) + PyVarObject_HEAD_INIT(NULL, 0) "_asyncio.FutureIter", .tp_basicsize = sizeof(futureiterobject), .tp_itemsize = 0, @@ -1189,7 +1189,7 @@ }; PyTypeObject TaskSendMethWrapper_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(NULL, 0) "TaskSendMethWrapper", .tp_basicsize = sizeof(TaskSendMethWrapper), .tp_itemsize = 0, @@ -1260,7 +1260,7 @@ } PyTypeObject TaskWakeupMethWrapper_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(NULL, 0) "TaskWakeupMethWrapper", .tp_basicsize = sizeof(TaskWakeupMethWrapper), .tp_itemsize = 0, @@ -1778,7 +1778,7 @@ }; static PyTypeObject TaskType = { - PyVarObject_HEAD_INIT(0, 0) + PyVarObject_HEAD_INIT(NULL, 0) "_asyncio.Task", sizeof(TaskObj), /* tp_basicsize */ .tp_base = &FutureType, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 14:20:15 2016 From: python-checkins at python.org (steve.dower) Date: Fri, 28 Oct 2016 18:20:15 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Removes_incorrect_condition_from_lib=5Fpdb=2Emsi?= Message-ID: <20161028182014.77021.89982.35DF129D@psf.io> https://hg.python.org/cpython/rev/d28bf161c8a3 changeset: 104780:d28bf161c8a3 branch: 3.6 parent: 104777:fb7c439103b9 parent: 104779:0bff26cfbac3 user: Steve Dower date: Fri Oct 28 11:19:42 2016 -0700 summary: Removes incorrect condition from lib_pdb.msi files: Tools/msi/lib/lib_files.wxs | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -22,7 +22,6 @@ - SYMBOLS=1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 14:20:14 2016 From: python-checkins at python.org (steve.dower) Date: Fri, 28 Oct 2016 18:20:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Removes_incorr?= =?utf-8?q?ect_condition_from_lib=5Fpdb=2Emsi?= Message-ID: <20161028182014.32162.11875.5F2A2C07@psf.io> https://hg.python.org/cpython/rev/0bff26cfbac3 changeset: 104779:0bff26cfbac3 branch: 3.5 parent: 104767:695cea018ba9 user: Steve Dower date: Fri Oct 28 11:19:18 2016 -0700 summary: Removes incorrect condition from lib_pdb.msi files: Tools/msi/lib/lib_files.wxs | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -22,7 +22,6 @@ - SYMBOLS=1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 14:20:14 2016 From: python-checkins at python.org (steve.dower) Date: Fri, 28 Oct 2016 18:20:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Removes_incorrect_condition_from_lib=5Fpdb=2Emsi?= Message-ID: <20161028182014.8196.40400.5F5EA083@psf.io> https://hg.python.org/cpython/rev/86b570d13f5a changeset: 104781:86b570d13f5a parent: 104778:245ee609feea parent: 104780:d28bf161c8a3 user: Steve Dower date: Fri Oct 28 11:19:50 2016 -0700 summary: Removes incorrect condition from lib_pdb.msi files: Tools/msi/lib/lib_files.wxs | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -22,7 +22,6 @@ - SYMBOLS=1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 18:49:14 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 28 Oct 2016 22:49:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTQ0?= =?utf-8?q?=3A_Fix_compilation_of_=5Fasynciomodule=2Ec_on_Windows?= Message-ID: <20161028224914.22590.74616.B551691C@psf.io> https://hg.python.org/cpython/rev/635f5854cb3e changeset: 104782:635f5854cb3e branch: 3.6 parent: 104780:d28bf161c8a3 user: Yury Selivanov date: Fri Oct 28 18:48:50 2016 -0400 summary: Issue #28544: Fix compilation of _asynciomodule.c on Windows files: Include/dictobject.h | 2 +- Include/genobject.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -112,7 +112,7 @@ PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); Py_ssize_t _PyDict_SizeOf(PyDictObject *); -PyObject *_PyDict_Pop(PyDictObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyDict_Pop(PyDictObject *, PyObject *, PyObject *); PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) diff --git a/Include/genobject.h b/Include/genobject.h --- a/Include/genobject.h +++ b/Include/genobject.h @@ -42,7 +42,7 @@ PyObject *name, PyObject *qualname); PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); -PyObject *_PyGen_Send(PyGenObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyGen_Send(PyGenObject *, PyObject *); PyObject *_PyGen_yf(PyGenObject *); PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 18:49:15 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 28 Oct 2016 22:49:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg1NDQp?= Message-ID: <20161028224915.25402.63961.463A093F@psf.io> https://hg.python.org/cpython/rev/9d95510dc203 changeset: 104783:9d95510dc203 parent: 104781:86b570d13f5a parent: 104782:635f5854cb3e user: Yury Selivanov date: Fri Oct 28 18:49:10 2016 -0400 summary: Merge 3.6 (issue #28544) files: Include/dictobject.h | 2 +- Include/genobject.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -112,7 +112,7 @@ PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); Py_ssize_t _PyDict_SizeOf(PyDictObject *); -PyObject *_PyDict_Pop(PyDictObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyDict_Pop(PyDictObject *, PyObject *, PyObject *); PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) diff --git a/Include/genobject.h b/Include/genobject.h --- a/Include/genobject.h +++ b/Include/genobject.h @@ -42,7 +42,7 @@ PyObject *name, PyObject *qualname); PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); -PyObject *_PyGen_Send(PyGenObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyGen_Send(PyGenObject *, PyObject *); PyObject *_PyGen_yf(PyGenObject *); PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 19:01:50 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 28 Oct 2016 23:01:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTQ0?= =?utf-8?q?=3A_Pass_=60PyObject*=60_to_=5FPyDict=5FPop=2C_not_=60PyDictObj?= =?utf-8?q?ect*=60?= Message-ID: <20161028230150.3133.33903.820762A6@psf.io> https://hg.python.org/cpython/rev/db7bcd92cf85 changeset: 104784:db7bcd92cf85 branch: 3.6 parent: 104782:635f5854cb3e user: Yury Selivanov date: Fri Oct 28 19:01:21 2016 -0400 summary: Issue #28544: Pass `PyObject*` to _PyDict_Pop, not `PyDictObject*` files: Include/dictobject.h | 2 +- Modules/_asynciomodule.c | 10 +++++----- Objects/dictobject.c | 8 ++++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -112,7 +112,7 @@ PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); Py_ssize_t _PyDict_SizeOf(PyDictObject *); -PyAPI_FUNC(PyObject *) _PyDict_Pop(PyDictObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *, PyObject *, PyObject *); PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -21,7 +21,7 @@ /* State of the _asyncio module */ static PyObject *all_tasks; -static PyDictObject *current_tasks; +static PyObject *current_tasks; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; static PyObject *asyncio_future_repr_info_func; @@ -1429,11 +1429,11 @@ return NULL; } - res = PyDict_GetItem((PyObject*)current_tasks, loop); + res = PyDict_GetItem(current_tasks, loop); Py_DECREF(loop); } else { - res = PyDict_GetItem((PyObject*)current_tasks, loop); + res = PyDict_GetItem(current_tasks, loop); } if (res == NULL) { @@ -2235,7 +2235,7 @@ PyObject *res; PyObject *ot; - if (PyDict_SetItem((PyObject *)current_tasks, + if (PyDict_SetItem(current_tasks, task->task_loop, (PyObject*)task) == -1) { return NULL; @@ -2385,7 +2385,7 @@ goto fail; } - current_tasks = (PyDictObject *)PyDict_New(); + current_tasks = PyDict_New(); if (current_tasks == NULL) { goto fail; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1768,13 +1768,17 @@ /* Internal version of dict.pop(). */ PyObject * -_PyDict_Pop(PyDictObject *mp, PyObject *key, PyObject *deflt) +_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt) { Py_hash_t hash; Py_ssize_t ix, hashpos; PyObject *old_value, *old_key; PyDictKeyEntry *ep; PyObject **value_addr; + PyDictObject *mp; + + assert(PyDict_Check(dict)); + mp = (PyDictObject *)dict; if (mp->ma_used == 0) { if (deflt) { @@ -2836,7 +2840,7 @@ if(!PyArg_UnpackTuple(args, "pop", 1, 2, &key, &deflt)) return NULL; - return _PyDict_Pop(mp, key, deflt); + return _PyDict_Pop((PyObject*)mp, key, deflt); } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Oct 28 19:01:50 2016 From: python-checkins at python.org (yury.selivanov) Date: Fri, 28 Oct 2016 23:01:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42IChpc3N1ZSAjMjg1NDQp?= Message-ID: <20161028230150.30849.6291.70C1E6C4@psf.io> https://hg.python.org/cpython/rev/60b6e820abe5 changeset: 104785:60b6e820abe5 parent: 104783:9d95510dc203 parent: 104784:db7bcd92cf85 user: Yury Selivanov date: Fri Oct 28 19:01:46 2016 -0400 summary: Merge 3.6 (issue #28544) files: Include/dictobject.h | 2 +- Modules/_asynciomodule.c | 10 +++++----- Objects/dictobject.c | 8 ++++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -112,7 +112,7 @@ PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); Py_ssize_t _PyDict_SizeOf(PyDictObject *); -PyAPI_FUNC(PyObject *) _PyDict_Pop(PyDictObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *, PyObject *, PyObject *); PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -21,7 +21,7 @@ /* State of the _asyncio module */ static PyObject *all_tasks; -static PyDictObject *current_tasks; +static PyObject *current_tasks; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; static PyObject *asyncio_future_repr_info_func; @@ -1429,11 +1429,11 @@ return NULL; } - res = PyDict_GetItem((PyObject*)current_tasks, loop); + res = PyDict_GetItem(current_tasks, loop); Py_DECREF(loop); } else { - res = PyDict_GetItem((PyObject*)current_tasks, loop); + res = PyDict_GetItem(current_tasks, loop); } if (res == NULL) { @@ -2235,7 +2235,7 @@ PyObject *res; PyObject *ot; - if (PyDict_SetItem((PyObject *)current_tasks, + if (PyDict_SetItem(current_tasks, task->task_loop, (PyObject*)task) == -1) { return NULL; @@ -2385,7 +2385,7 @@ goto fail; } - current_tasks = (PyDictObject *)PyDict_New(); + current_tasks = PyDict_New(); if (current_tasks == NULL) { goto fail; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1769,13 +1769,17 @@ /* Internal version of dict.pop(). */ PyObject * -_PyDict_Pop(PyDictObject *mp, PyObject *key, PyObject *deflt) +_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt) { Py_hash_t hash; Py_ssize_t ix, hashpos; PyObject *old_value, *old_key; PyDictKeyEntry *ep; PyObject **value_addr; + PyDictObject *mp; + + assert(PyDict_Check(dict)); + mp = (PyDictObject *)dict; if (mp->ma_used == 0) { if (deflt) { @@ -2837,7 +2841,7 @@ if(!PyArg_UnpackTuple(args, "pop", 1, 2, &key, &deflt)) return NULL; - return _PyDict_Pop(mp, key, deflt); + return _PyDict_Pop((PyObject*)mp, key, deflt); } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 03:12:35 2016 From: python-checkins at python.org (victor.stinner) Date: Sat, 29 Oct 2016 07:12:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTQ0?= =?utf-8?q?=3A_Fix_inefficient_call_to_=5FPyObject=5FCallMethodId=28=29?= Message-ID: <20161029071235.114891.44624.255A2CE0@psf.io> https://hg.python.org/cpython/rev/950fbd75223b changeset: 104786:950fbd75223b branch: 3.6 parent: 104784:db7bcd92cf85 user: Victor Stinner date: Sat Oct 29 09:05:39 2016 +0200 summary: Issue #28544: Fix inefficient call to _PyObject_CallMethodId() "()" format string creates an empty list of argument but requires extra work to parse the format string. files: Modules/_asynciomodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -152,7 +152,7 @@ Py_CLEAR(fut->fut_loop); fut->fut_loop = loop; - res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); + res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, NULL); if (res == NULL) { return -1; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 03:12:36 2016 From: python-checkins at python.org (victor.stinner) Date: Sat, 29 Oct 2016 07:12:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy42?= Message-ID: <20161029071235.114864.40950.164556F7@psf.io> https://hg.python.org/cpython/rev/09a7153bf791 changeset: 104787:09a7153bf791 parent: 104785:60b6e820abe5 parent: 104786:950fbd75223b user: Victor Stinner date: Sat Oct 29 09:11:06 2016 +0200 summary: Merge 3.6 files: Modules/_asynciomodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -152,7 +152,7 @@ Py_CLEAR(fut->fut_loop); fut->fut_loop = loop; - res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); + res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, NULL); if (res == NULL) { return -1; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 03:50:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 29 Oct 2016 07:50:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328199=3A_Microoptimized_dict_resizing=2E__Based?= =?utf-8?q?_on_patch_by_Naoki_Inada=2E?= Message-ID: <20161029075021.7081.57711.356AE943@psf.io> https://hg.python.org/cpython/rev/f0fbc6071d7e changeset: 104789:f0fbc6071d7e parent: 104787:09a7153bf791 parent: 104788:6b88dfc7b25d user: Serhiy Storchaka date: Sat Oct 29 10:50:00 2016 +0300 summary: Issue #28199: Microoptimized dict resizing. Based on patch by Naoki Inada. files: Objects/dictobject.c | 123 +++++++++++++++--------------- 1 files changed, 63 insertions(+), 60 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1196,41 +1196,21 @@ } /* -Internal routine used by dictresize() to insert an item which is -known to be absent from the dict. This routine also assumes that -the dict contains no deleted entries. Besides the performance benefit, -using insertdict() in dictresize() is dangerous (SF bug #1456209). -Note that no refcounts are changed by this routine; if needed, the caller -is responsible for incref'ing `key` and `value`. -Neither mp->ma_used nor k->dk_usable are modified by this routine; the caller -must set them correctly +Internal routine used by dictresize() to buid a hashtable of entries. */ static void -insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, - PyObject *value) +build_indices(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n) { - size_t i; - PyDictKeysObject *k = mp->ma_keys; - size_t mask = (size_t)DK_SIZE(k)-1; - PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); - PyDictKeyEntry *ep; - - assert(k->dk_lookup != NULL); - assert(value != NULL); - assert(key != NULL); - assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); - i = hash & mask; - for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { - perturb >>= PERTURB_SHIFT; - i = mask & ((i << 2) + i + perturb + 1); + size_t mask = (size_t)DK_SIZE(keys) - 1; + for (Py_ssize_t ix = 0; ix != n; ix++, ep++) { + Py_hash_t hash = ep->me_hash; + size_t i = hash & mask; + for (size_t perturb = hash; dk_get_index(keys, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; + i = mask & ((i << 2) + i + perturb + 1); + } + dk_set_index(keys, i, ix); } - ep = &ep0[k->dk_nentries]; - assert(ep->me_value == NULL); - dk_set_index(k, i, k->dk_nentries); - k->dk_nentries++; - ep->me_key = key; - ep->me_hash = hash; - ep->me_value = value; } /* @@ -1246,10 +1226,10 @@ static int dictresize(PyDictObject *mp, Py_ssize_t minused) { - Py_ssize_t i, newsize; + Py_ssize_t newsize, numentries; PyDictKeysObject *oldkeys; PyObject **oldvalues; - PyDictKeyEntry *ep0; + PyDictKeyEntry *oldentries, *newentries; /* Find the smallest table size > minused. */ for (newsize = PyDict_MINSIZE; @@ -1260,8 +1240,14 @@ PyErr_NoMemory(); return -1; } + oldkeys = mp->ma_keys; - oldvalues = mp->ma_values; + + /* NOTE: Current odict checks mp->ma_keys to detect resize happen. + * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. + * TODO: Try reusing oldkeys when reimplement odict. + */ + /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { @@ -1270,42 +1256,59 @@ } if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; - mp->ma_values = NULL; - ep0 = DK_ENTRIES(oldkeys); - /* Main loop below assumes we can transfer refcount to new keys - * and that value is stored in me_value. - * Increment ref-counts and copy values here to compensate - * This (resizing a split table) should be relatively rare */ + + numentries = mp->ma_used; + oldentries = DK_ENTRIES(oldkeys); + newentries = DK_ENTRIES(mp->ma_keys); + oldvalues = mp->ma_values; if (oldvalues != NULL) { - for (i = 0; i < oldkeys->dk_nentries; i++) { - if (oldvalues[i] != NULL) { - Py_INCREF(ep0[i].me_key); - ep0[i].me_value = oldvalues[i]; - } + /* Convert split table into new combined table. + * We must incref keys; we can transfer values. + * Note that values of split table is always dense. + */ + for (Py_ssize_t i = 0; i < numentries; i++) { + assert(oldvalues[i] != NULL); + PyDictKeyEntry *ep = &oldentries[i]; + PyObject *key = ep->me_key; + Py_INCREF(key); + newentries[i].me_key = key; + newentries[i].me_hash = ep->me_hash; + newentries[i].me_value = oldvalues[i]; } - } - /* Main loop */ - for (i = 0; i < oldkeys->dk_nentries; i++) { - PyDictKeyEntry *ep = &ep0[i]; - if (ep->me_value != NULL) { - insertdict_clean(mp, ep->me_key, ep->me_hash, ep->me_value); - } - } - mp->ma_keys->dk_usable -= mp->ma_used; - if (oldvalues != NULL) { - /* NULL out me_value slot in oldkeys, in case it was shared */ - for (i = 0; i < oldkeys->dk_nentries; i++) - ep0[i].me_value = NULL; + DK_DECREF(oldkeys); + mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); } } - else { + else { // combined table. + if (oldkeys->dk_nentries == numentries) { + memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); + } + else { + PyDictKeyEntry *ep = oldentries; + for (Py_ssize_t i = 0; i < numentries; i++) { + while (ep->me_value == NULL) + ep++; + newentries[i] = *ep++; + } + } + assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); - DK_DEBUG_DECREF PyObject_FREE(oldkeys); + if (oldkeys->dk_size == PyDict_MINSIZE && + numfreekeys < PyDict_MAXFREELIST) { + DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; + } + else { + DK_DEBUG_DECREF PyObject_FREE(oldkeys); + } } + + build_indices(mp->ma_keys, newentries, numentries); + mp->ma_keys->dk_usable -= numentries; + mp->ma_keys->dk_nentries = numentries; return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 03:50:21 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 29 Oct 2016 07:50:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MTk5?= =?utf-8?q?=3A_Microoptimized_dict_resizing=2E__Based_on_patch_by_Naoki_In?= =?utf-8?q?ada=2E?= Message-ID: <20161029075021.25301.15599.682CC08D@psf.io> https://hg.python.org/cpython/rev/6b88dfc7b25d changeset: 104788:6b88dfc7b25d branch: 3.6 parent: 104786:950fbd75223b user: Serhiy Storchaka date: Sat Oct 29 10:49:43 2016 +0300 summary: Issue #28199: Microoptimized dict resizing. Based on patch by Naoki Inada. files: Objects/dictobject.c | 123 +++++++++++++++--------------- 1 files changed, 63 insertions(+), 60 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1195,41 +1195,21 @@ } /* -Internal routine used by dictresize() to insert an item which is -known to be absent from the dict. This routine also assumes that -the dict contains no deleted entries. Besides the performance benefit, -using insertdict() in dictresize() is dangerous (SF bug #1456209). -Note that no refcounts are changed by this routine; if needed, the caller -is responsible for incref'ing `key` and `value`. -Neither mp->ma_used nor k->dk_usable are modified by this routine; the caller -must set them correctly +Internal routine used by dictresize() to buid a hashtable of entries. */ static void -insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, - PyObject *value) +build_indices(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n) { - size_t i; - PyDictKeysObject *k = mp->ma_keys; - size_t mask = (size_t)DK_SIZE(k)-1; - PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); - PyDictKeyEntry *ep; - - assert(k->dk_lookup != NULL); - assert(value != NULL); - assert(key != NULL); - assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); - i = hash & mask; - for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { - perturb >>= PERTURB_SHIFT; - i = mask & ((i << 2) + i + perturb + 1); + size_t mask = (size_t)DK_SIZE(keys) - 1; + for (Py_ssize_t ix = 0; ix != n; ix++, ep++) { + Py_hash_t hash = ep->me_hash; + size_t i = hash & mask; + for (size_t perturb = hash; dk_get_index(keys, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; + i = mask & ((i << 2) + i + perturb + 1); + } + dk_set_index(keys, i, ix); } - ep = &ep0[k->dk_nentries]; - assert(ep->me_value == NULL); - dk_set_index(k, i, k->dk_nentries); - k->dk_nentries++; - ep->me_key = key; - ep->me_hash = hash; - ep->me_value = value; } /* @@ -1245,10 +1225,10 @@ static int dictresize(PyDictObject *mp, Py_ssize_t minused) { - Py_ssize_t i, newsize; + Py_ssize_t newsize, numentries; PyDictKeysObject *oldkeys; PyObject **oldvalues; - PyDictKeyEntry *ep0; + PyDictKeyEntry *oldentries, *newentries; /* Find the smallest table size > minused. */ for (newsize = PyDict_MINSIZE; @@ -1259,8 +1239,14 @@ PyErr_NoMemory(); return -1; } + oldkeys = mp->ma_keys; - oldvalues = mp->ma_values; + + /* NOTE: Current odict checks mp->ma_keys to detect resize happen. + * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. + * TODO: Try reusing oldkeys when reimplement odict. + */ + /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { @@ -1269,42 +1255,59 @@ } if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; - mp->ma_values = NULL; - ep0 = DK_ENTRIES(oldkeys); - /* Main loop below assumes we can transfer refcount to new keys - * and that value is stored in me_value. - * Increment ref-counts and copy values here to compensate - * This (resizing a split table) should be relatively rare */ + + numentries = mp->ma_used; + oldentries = DK_ENTRIES(oldkeys); + newentries = DK_ENTRIES(mp->ma_keys); + oldvalues = mp->ma_values; if (oldvalues != NULL) { - for (i = 0; i < oldkeys->dk_nentries; i++) { - if (oldvalues[i] != NULL) { - Py_INCREF(ep0[i].me_key); - ep0[i].me_value = oldvalues[i]; - } + /* Convert split table into new combined table. + * We must incref keys; we can transfer values. + * Note that values of split table is always dense. + */ + for (Py_ssize_t i = 0; i < numentries; i++) { + assert(oldvalues[i] != NULL); + PyDictKeyEntry *ep = &oldentries[i]; + PyObject *key = ep->me_key; + Py_INCREF(key); + newentries[i].me_key = key; + newentries[i].me_hash = ep->me_hash; + newentries[i].me_value = oldvalues[i]; } - } - /* Main loop */ - for (i = 0; i < oldkeys->dk_nentries; i++) { - PyDictKeyEntry *ep = &ep0[i]; - if (ep->me_value != NULL) { - insertdict_clean(mp, ep->me_key, ep->me_hash, ep->me_value); - } - } - mp->ma_keys->dk_usable -= mp->ma_used; - if (oldvalues != NULL) { - /* NULL out me_value slot in oldkeys, in case it was shared */ - for (i = 0; i < oldkeys->dk_nentries; i++) - ep0[i].me_value = NULL; + DK_DECREF(oldkeys); + mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); } } - else { + else { // combined table. + if (oldkeys->dk_nentries == numentries) { + memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); + } + else { + PyDictKeyEntry *ep = oldentries; + for (Py_ssize_t i = 0; i < numentries; i++) { + while (ep->me_value == NULL) + ep++; + newentries[i] = *ep++; + } + } + assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); - DK_DEBUG_DECREF PyObject_FREE(oldkeys); + if (oldkeys->dk_size == PyDict_MINSIZE && + numfreekeys < PyDict_MAXFREELIST) { + DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; + } + else { + DK_DEBUG_DECREF PyObject_FREE(oldkeys); + } } + + build_indices(mp->ma_keys, newentries, numentries); + mp->ma_keys->dk_usable -= numentries; + mp->ma_keys->dk_nentries = numentries; return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:01:46 2016 From: python-checkins at python.org (xavier.degaye) Date: Sat, 29 Oct 2016 15:01:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDQ0?= =?utf-8?q?=3A_Fix_missing_extensions_modules_when_cross_compiling=2E?= Message-ID: <20161029150145.16974.29670.39BCCCD3@psf.io> https://hg.python.org/cpython/rev/4b2679a06ace changeset: 104790:4b2679a06ace branch: 3.5 parent: 104779:0bff26cfbac3 user: Xavier de Gaye date: Sat Oct 29 16:57:20 2016 +0200 summary: Issue #28444: Fix missing extensions modules when cross compiling. files: Makefile.pre.in | 1 + Misc/NEWS | 2 + Modules/makesetup | 5 +++- setup.py | 41 +++++++++++++++++----------------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -20,6 +20,7 @@ # === Variables set by makesetup === +MODNAMES= _MODNAMES_ MODOBJS= _MODOBJS_ MODLIBS= _MODLIBS_ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -502,6 +502,8 @@ Build ----- +- Issue #28444: Fix missing extensions modules when cross compiling. + - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. - Issue #28258: Fixed build with Estonian locale (python-config and distclean diff --git a/Modules/makesetup b/Modules/makesetup --- a/Modules/makesetup +++ b/Modules/makesetup @@ -29,6 +29,7 @@ # # Copying Makefile.pre to Makefile: # - insert an identifying comment at the start +# - replace _MODNAMES_ by the list of modules from Setup # - replace _MODOBJS_ by the list of objects from Setup (except for # Setup files after a -n option) # - replace _MODLIBS_ by the list of libraries from Setup @@ -110,6 +111,7 @@ # Rules appended by makedepend " >$rulesf DEFS= + NAMES= MODS= SHAREDMODS= OBJS= @@ -181,7 +183,7 @@ *.*) echo 1>&2 "bad word $arg in $line" exit 1;; -u) skip=libs; libs="$libs -u";; - [a-zA-Z_]*) mods="$mods $arg";; + [a-zA-Z_]*) NAMES="$NAMES $arg"; mods="$mods $arg";; *) echo 1>&2 "bad word $arg in $line" exit 1;; esac @@ -280,6 +282,7 @@ echo "1i\\" >$sedf str="# Generated automatically from $makepre by makesetup." echo "$str" >>$sedf + echo "s%_MODNAMES_%$NAMES%" >>$sedf echo "s%_MODOBJS_%$OBJS%" >>$sedf echo "s%_MODLIBS_%$LIBS%" >>$sedf echo "/Definitions added by makesetup/a$NL$NL$DEFS" >>$sedf diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -8,7 +8,6 @@ import sysconfig from distutils import log -from distutils import text_file from distutils.errors import * from distutils.core import Extension, setup from distutils.command.build_ext import build_ext @@ -230,7 +229,12 @@ headers = [sysconfig.get_config_h_filename()] headers += glob(os.path.join(sysconfig.get_path('include'), "*.h")) - for ext in self.extensions[:]: + # The sysconfig variable built by makesetup, listing the already + # built modules as configured by the Setup files. + modnames = sysconfig.get_config_var('MODNAMES').split() + + removed_modules = [] + for ext in self.extensions: ext.sources = [ find_module_file(filename, moddirlist) for filename in ext.sources ] if ext.depends is not None: @@ -241,26 +245,14 @@ # re-compile extensions if a header file has been changed ext.depends.extend(headers) - # If a module has already been built statically, - # don't build it here - if ext.name in sys.builtin_module_names: - self.extensions.remove(ext) + # If a module has already been built by the Makefile, + # don't build it here. + if ext.name in modnames: + removed_modules.append(ext) - # Parse Modules/Setup and Modules/Setup.local to figure out which - # modules are turned on in the file. - remove_modules = [] - for filename in ('Modules/Setup', 'Modules/Setup.local'): - input = text_file.TextFile(filename, join_lines=1) - while 1: - line = input.readline() - if not line: break - line = line.split() - remove_modules.append(line[0]) - input.close() - - for ext in self.extensions[:]: - if ext.name in remove_modules: - self.extensions.remove(ext) + if removed_modules: + self.extensions = [x for x in self.extensions if x not in + removed_modules] # When you run "make CC=altcc" or something similar, you really want # those environment variables passed into the setup.py phase. Here's @@ -303,6 +295,13 @@ " detect_modules() for the module's name.") print() + if removed_modules: + print("The following modules found by detect_modules() in" + " setup.py, have been") + print("built by the Makefile instead, as configured by the" + " Setup files:") + print_three_column([ext.name for ext in removed_modules]) + if self.failed: failed = self.failed[:] print() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:01:46 2016 From: python-checkins at python.org (xavier.degaye) Date: Sat, 29 Oct 2016 15:01:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328444=3A_Merge_with_3=2E6=2E?= Message-ID: <20161029150146.62801.18104.6CDB4C04@psf.io> https://hg.python.org/cpython/rev/a87d4324e804 changeset: 104792:a87d4324e804 parent: 104789:f0fbc6071d7e parent: 104791:cddb7b2aba34 user: Xavier de Gaye date: Sat Oct 29 17:01:07 2016 +0200 summary: Issue #28444: Merge with 3.6. files: Makefile.pre.in | 1 + Misc/NEWS | 2 + Modules/makesetup | 5 +++- setup.py | 41 +++++++++++++++++----------------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -20,6 +20,7 @@ # === Variables set by makesetup === +MODNAMES= _MODNAMES_ MODOBJS= _MODOBJS_ MODLIBS= _MODLIBS_ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -357,6 +357,8 @@ Build ----- +- Issue #28444: Fix missing extensions modules when cross compiling. + - Issue #28208: Update Windows build to use SQLite 3.14.2.0. - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. diff --git a/Modules/makesetup b/Modules/makesetup --- a/Modules/makesetup +++ b/Modules/makesetup @@ -29,6 +29,7 @@ # # Copying Makefile.pre to Makefile: # - insert an identifying comment at the start +# - replace _MODNAMES_ by the list of modules from Setup # - replace _MODOBJS_ by the list of objects from Setup (except for # Setup files after a -n option) # - replace _MODLIBS_ by the list of libraries from Setup @@ -110,6 +111,7 @@ # Rules appended by makedepend " >$rulesf DEFS= + NAMES= MODS= SHAREDMODS= OBJS= @@ -181,7 +183,7 @@ *.*) echo 1>&2 "bad word $arg in $line" exit 1;; -u) skip=libs; libs="$libs -u";; - [a-zA-Z_]*) mods="$mods $arg";; + [a-zA-Z_]*) NAMES="$NAMES $arg"; mods="$mods $arg";; *) echo 1>&2 "bad word $arg in $line" exit 1;; esac @@ -280,6 +282,7 @@ echo "1i\\" >$sedf str="# Generated automatically from $makepre by makesetup." echo "$str" >>$sedf + echo "s%_MODNAMES_%$NAMES%" >>$sedf echo "s%_MODOBJS_%$OBJS%" >>$sedf echo "s%_MODLIBS_%$LIBS%" >>$sedf echo "/Definitions added by makesetup/a$NL$NL$DEFS" >>$sedf diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -8,7 +8,6 @@ import sysconfig from distutils import log -from distutils import text_file from distutils.errors import * from distutils.core import Extension, setup from distutils.command.build_ext import build_ext @@ -230,7 +229,12 @@ headers = [sysconfig.get_config_h_filename()] headers += glob(os.path.join(sysconfig.get_path('include'), "*.h")) - for ext in self.extensions[:]: + # The sysconfig variable built by makesetup, listing the already + # built modules as configured by the Setup files. + modnames = sysconfig.get_config_var('MODNAMES').split() + + removed_modules = [] + for ext in self.extensions: ext.sources = [ find_module_file(filename, moddirlist) for filename in ext.sources ] if ext.depends is not None: @@ -241,26 +245,14 @@ # re-compile extensions if a header file has been changed ext.depends.extend(headers) - # If a module has already been built statically, - # don't build it here - if ext.name in sys.builtin_module_names: - self.extensions.remove(ext) + # If a module has already been built by the Makefile, + # don't build it here. + if ext.name in modnames: + removed_modules.append(ext) - # Parse Modules/Setup and Modules/Setup.local to figure out which - # modules are turned on in the file. - remove_modules = [] - for filename in ('Modules/Setup', 'Modules/Setup.local'): - input = text_file.TextFile(filename, join_lines=1) - while 1: - line = input.readline() - if not line: break - line = line.split() - remove_modules.append(line[0]) - input.close() - - for ext in self.extensions[:]: - if ext.name in remove_modules: - self.extensions.remove(ext) + if removed_modules: + self.extensions = [x for x in self.extensions if x not in + removed_modules] # When you run "make CC=altcc" or something similar, you really want # those environment variables passed into the setup.py phase. Here's @@ -303,6 +295,13 @@ " detect_modules() for the module's name.") print() + if removed_modules: + print("The following modules found by detect_modules() in" + " setup.py, have been") + print("built by the Makefile instead, as configured by the" + " Setup files:") + print_three_column([ext.name for ext in removed_modules]) + if self.failed: failed = self.failed[:] print() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:01:47 2016 From: python-checkins at python.org (xavier.degaye) Date: Sat, 29 Oct 2016 15:01:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328444=3A_Merge_with_3=2E5=2E?= Message-ID: <20161029150146.31769.22047.A7401688@psf.io> https://hg.python.org/cpython/rev/cddb7b2aba34 changeset: 104791:cddb7b2aba34 branch: 3.6 parent: 104788:6b88dfc7b25d parent: 104790:4b2679a06ace user: Xavier de Gaye date: Sat Oct 29 16:59:32 2016 +0200 summary: Issue #28444: Merge with 3.5. files: Makefile.pre.in | 1 + Misc/NEWS | 2 + Modules/makesetup | 5 +++- setup.py | 41 +++++++++++++++++----------------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -20,6 +20,7 @@ # === Variables set by makesetup === +MODNAMES= _MODNAMES_ MODOBJS= _MODOBJS_ MODLIBS= _MODLIBS_ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -95,6 +95,8 @@ Build ----- +- Issue #28444: Fix missing extensions modules when cross compiling. + - Issue #28208: Update Windows build to use SQLite 3.14.2.0. - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. diff --git a/Modules/makesetup b/Modules/makesetup --- a/Modules/makesetup +++ b/Modules/makesetup @@ -29,6 +29,7 @@ # # Copying Makefile.pre to Makefile: # - insert an identifying comment at the start +# - replace _MODNAMES_ by the list of modules from Setup # - replace _MODOBJS_ by the list of objects from Setup (except for # Setup files after a -n option) # - replace _MODLIBS_ by the list of libraries from Setup @@ -110,6 +111,7 @@ # Rules appended by makedepend " >$rulesf DEFS= + NAMES= MODS= SHAREDMODS= OBJS= @@ -181,7 +183,7 @@ *.*) echo 1>&2 "bad word $arg in $line" exit 1;; -u) skip=libs; libs="$libs -u";; - [a-zA-Z_]*) mods="$mods $arg";; + [a-zA-Z_]*) NAMES="$NAMES $arg"; mods="$mods $arg";; *) echo 1>&2 "bad word $arg in $line" exit 1;; esac @@ -280,6 +282,7 @@ echo "1i\\" >$sedf str="# Generated automatically from $makepre by makesetup." echo "$str" >>$sedf + echo "s%_MODNAMES_%$NAMES%" >>$sedf echo "s%_MODOBJS_%$OBJS%" >>$sedf echo "s%_MODLIBS_%$LIBS%" >>$sedf echo "/Definitions added by makesetup/a$NL$NL$DEFS" >>$sedf diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -8,7 +8,6 @@ import sysconfig from distutils import log -from distutils import text_file from distutils.errors import * from distutils.core import Extension, setup from distutils.command.build_ext import build_ext @@ -230,7 +229,12 @@ headers = [sysconfig.get_config_h_filename()] headers += glob(os.path.join(sysconfig.get_path('include'), "*.h")) - for ext in self.extensions[:]: + # The sysconfig variable built by makesetup, listing the already + # built modules as configured by the Setup files. + modnames = sysconfig.get_config_var('MODNAMES').split() + + removed_modules = [] + for ext in self.extensions: ext.sources = [ find_module_file(filename, moddirlist) for filename in ext.sources ] if ext.depends is not None: @@ -241,26 +245,14 @@ # re-compile extensions if a header file has been changed ext.depends.extend(headers) - # If a module has already been built statically, - # don't build it here - if ext.name in sys.builtin_module_names: - self.extensions.remove(ext) + # If a module has already been built by the Makefile, + # don't build it here. + if ext.name in modnames: + removed_modules.append(ext) - # Parse Modules/Setup and Modules/Setup.local to figure out which - # modules are turned on in the file. - remove_modules = [] - for filename in ('Modules/Setup', 'Modules/Setup.local'): - input = text_file.TextFile(filename, join_lines=1) - while 1: - line = input.readline() - if not line: break - line = line.split() - remove_modules.append(line[0]) - input.close() - - for ext in self.extensions[:]: - if ext.name in remove_modules: - self.extensions.remove(ext) + if removed_modules: + self.extensions = [x for x in self.extensions if x not in + removed_modules] # When you run "make CC=altcc" or something similar, you really want # those environment variables passed into the setup.py phase. Here's @@ -303,6 +295,13 @@ " detect_modules() for the module's name.") print() + if removed_modules: + print("The following modules found by detect_modules() in" + " setup.py, have been") + print("built by the Makefile instead, as configured by the" + " Setup files:") + print_three_column([ext.name for ext in removed_modules]) + if self.failed: failed = self.failed[:] print() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:51:17 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 29 Oct 2016 15:51:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogTWFrZXMgdGVzdF91?= =?utf-8?q?nderpth*_tests_more_robust_by_copying_the_executable=2E?= Message-ID: <20161029155117.62991.36824.27C7BD6B@psf.io> https://hg.python.org/cpython/rev/0c910ea1c968 changeset: 104793:0c910ea1c968 branch: 3.6 parent: 104791:cddb7b2aba34 user: Steve Dower date: Sat Oct 29 08:50:31 2016 -0700 summary: Makes test_underpth* tests more robust by copying the executable. files: Lib/test/test_site.py | 73 ++++++++++++++++++++---------- PCbuild/rt.bat | 3 + 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -14,6 +14,7 @@ import encodings import urllib.request import urllib.error +import shutil import subprocess import sysconfig from copy import copy @@ -488,22 +489,44 @@ 'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()") + @classmethod + def _create_underpth_exe(self, lines): + exe_file = os.path.join(os.getenv('TEMP'), os.path.split(sys.executable)[1]) + shutil.copy(sys.executable, exe_file) + + _pth_file = os.path.splitext(exe_file)[0] + '._pth' + try: + with open(_pth_file, 'w') as f: + for line in lines: + print(line, file=f) + return exe_file + except: + os.unlink(_pth_file) + os.unlink(exe_file) + raise + + @classmethod + def _cleanup_underpth_exe(self, exe_file): + _pth_file = os.path.splitext(exe_file)[0] + '._pth' + os.unlink(_pth_file) + os.unlink(exe_file) + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") def test_underpth_nosite_file(self): - _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + exe_prefix = os.path.dirname(sys.executable) + exe_file = self._create_underpth_exe([ + 'fake-path-name', + *[libpath for _ in range(200)], + '# comment', + 'import site' + ]) + try: - libpath = os.path.dirname(os.path.dirname(encodings.__file__)) - with open(_pth_file, 'w') as f: - print('fake-path-name', file=f) - # Ensure the generated path is very long so that buffer - # resizing in getpathp.c is exercised - for _ in range(200): - print(libpath, file=f) - print('# comment', file=f) - env = os.environ.copy() env['PYTHONPATH'] = 'from-env' - rc = subprocess.call([sys.executable, '-c', + env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH')) + rc = subprocess.call([exe_file, '-c', 'import sys; sys.exit(sys.flags.no_site and ' 'len(sys.path) > 200 and ' '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( @@ -511,34 +534,34 @@ libpath, os.path.join(sys.prefix, 'from-env'), )], env=env) - self.assertEqual(rc, 0) finally: - os.unlink(_pth_file) + self._cleanup_underpth_exe(exe_file) + self.assertEqual(rc, 0) @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") def test_underpth_file(self): - _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + exe_prefix = os.path.dirname(sys.executable) + exe_file = self._create_underpth_exe([ + 'fake-path-name', + *[libpath for _ in range(200)], + '# comment', + 'import site' + ]) try: - libpath = os.path.dirname(os.path.dirname(encodings.__file__)) - with open(_pth_file, 'w') as f: - print('fake-path-name', file=f) - for _ in range(200): - print(libpath, file=f) - print('# comment', file=f) - print('import site', file=f) - env = os.environ.copy() env['PYTHONPATH'] = 'from-env' - rc = subprocess.call([sys.executable, '-c', + env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH')) + rc = subprocess.call([exe_file, '-c', 'import sys; sys.exit(not sys.flags.no_site and ' '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( os.path.join(sys.prefix, 'fake-path-name'), libpath, os.path.join(sys.prefix, 'from-env'), )], env=env) - self.assertEqual(rc, 0) finally: - os.unlink(_pth_file) + self._cleanup_underpth_exe(exe_file) + self.assertEqual(rc, 0) if __name__ == "__main__": diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -48,6 +48,9 @@ echo Deleting .pyc/.pyo files ... "%exe%" "%pcbuild%rmpyc.py" +echo Cleaning _pth files ... +if exist %prefix%*._pth del %prefix%*._pth + echo on %cmd% @echo off -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:51:18 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 29 Oct 2016 15:51:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Merge_from_3=2E6?= Message-ID: <20161029155117.25747.94565.79D86926@psf.io> https://hg.python.org/cpython/rev/3bd783323d44 changeset: 104794:3bd783323d44 parent: 104792:a87d4324e804 parent: 104793:0c910ea1c968 user: Steve Dower date: Sat Oct 29 08:50:42 2016 -0700 summary: Merge from 3.6 files: Lib/test/test_site.py | 73 ++++++++++++++++++++---------- PCbuild/rt.bat | 3 + 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -14,6 +14,7 @@ import encodings import urllib.request import urllib.error +import shutil import subprocess import sysconfig from copy import copy @@ -488,22 +489,44 @@ 'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()") + @classmethod + def _create_underpth_exe(self, lines): + exe_file = os.path.join(os.getenv('TEMP'), os.path.split(sys.executable)[1]) + shutil.copy(sys.executable, exe_file) + + _pth_file = os.path.splitext(exe_file)[0] + '._pth' + try: + with open(_pth_file, 'w') as f: + for line in lines: + print(line, file=f) + return exe_file + except: + os.unlink(_pth_file) + os.unlink(exe_file) + raise + + @classmethod + def _cleanup_underpth_exe(self, exe_file): + _pth_file = os.path.splitext(exe_file)[0] + '._pth' + os.unlink(_pth_file) + os.unlink(exe_file) + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") def test_underpth_nosite_file(self): - _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + exe_prefix = os.path.dirname(sys.executable) + exe_file = self._create_underpth_exe([ + 'fake-path-name', + *[libpath for _ in range(200)], + '# comment', + 'import site' + ]) + try: - libpath = os.path.dirname(os.path.dirname(encodings.__file__)) - with open(_pth_file, 'w') as f: - print('fake-path-name', file=f) - # Ensure the generated path is very long so that buffer - # resizing in getpathp.c is exercised - for _ in range(200): - print(libpath, file=f) - print('# comment', file=f) - env = os.environ.copy() env['PYTHONPATH'] = 'from-env' - rc = subprocess.call([sys.executable, '-c', + env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH')) + rc = subprocess.call([exe_file, '-c', 'import sys; sys.exit(sys.flags.no_site and ' 'len(sys.path) > 200 and ' '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( @@ -511,34 +534,34 @@ libpath, os.path.join(sys.prefix, 'from-env'), )], env=env) - self.assertEqual(rc, 0) finally: - os.unlink(_pth_file) + self._cleanup_underpth_exe(exe_file) + self.assertEqual(rc, 0) @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") def test_underpth_file(self): - _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + exe_prefix = os.path.dirname(sys.executable) + exe_file = self._create_underpth_exe([ + 'fake-path-name', + *[libpath for _ in range(200)], + '# comment', + 'import site' + ]) try: - libpath = os.path.dirname(os.path.dirname(encodings.__file__)) - with open(_pth_file, 'w') as f: - print('fake-path-name', file=f) - for _ in range(200): - print(libpath, file=f) - print('# comment', file=f) - print('import site', file=f) - env = os.environ.copy() env['PYTHONPATH'] = 'from-env' - rc = subprocess.call([sys.executable, '-c', + env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH')) + rc = subprocess.call([exe_file, '-c', 'import sys; sys.exit(not sys.flags.no_site and ' '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( os.path.join(sys.prefix, 'fake-path-name'), libpath, os.path.join(sys.prefix, 'from-env'), )], env=env) - self.assertEqual(rc, 0) finally: - os.unlink(_pth_file) + self._cleanup_underpth_exe(exe_file) + self.assertEqual(rc, 0) if __name__ == "__main__": diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -48,6 +48,9 @@ echo Deleting .pyc/.pyo files ... "%exe%" "%pcbuild%rmpyc.py" +echo Cleaning _pth files ... +if exist %prefix%*._pth del %prefix%*._pth + echo on %cmd% @echo off -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:55:13 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 15:55:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzI4NTU2OiB1cGRhdGVzIHRvIHR5cGluZy5weSAoMy42LT4z?= =?utf-8?b?Ljcp?= Message-ID: <20161029155513.32195.80544.E5E8E71C@psf.io> https://hg.python.org/cpython/rev/2c75b13ccf82 changeset: 104797:2c75b13ccf82 parent: 104794:3bd783323d44 parent: 104796:d2b5c3bfa2b5 user: Guido van Rossum date: Sat Oct 29 08:54:58 2016 -0700 summary: Issue #28556: updates to typing.py (3.6->3.7) files: Lib/test/test_typing.py | 157 +++++- Lib/typing.py | 754 +++++++++++++++------------ 2 files changed, 548 insertions(+), 363 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -142,8 +142,9 @@ self.assertEqual(Union[X, X], X) self.assertNotEqual(Union[X, int], Union[X]) self.assertNotEqual(Union[X, int], Union[int]) - self.assertEqual(Union[X, int].__union_params__, (X, int)) - self.assertEqual(Union[X, int].__union_set_params__, {X, int}) + self.assertEqual(Union[X, int].__args__, (X, int)) + self.assertEqual(Union[X, int].__parameters__, (X,)) + self.assertIs(Union[X, int].__origin__, Union) def test_union_constrained(self): A = TypeVar('A', str, bytes) @@ -312,8 +313,6 @@ def test_basics(self): with self.assertRaises(TypeError): - issubclass(Tuple[int, str], Tuple) - with self.assertRaises(TypeError): issubclass(Tuple, Tuple[int, str]) with self.assertRaises(TypeError): issubclass(tuple, Tuple[int, str]) @@ -367,22 +366,6 @@ self.assertNotEqual(Callable[[int], int], Callable[[], int]) self.assertNotEqual(Callable[[int], int], Callable) - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - - class C(Callable): - pass - - with self.assertRaises(TypeError): - - class C(type(Callable)): - pass - - with self.assertRaises(TypeError): - - class C(Callable[[int], int]): - pass - def test_cannot_instantiate(self): with self.assertRaises(TypeError): Callable() @@ -710,6 +693,138 @@ self.assertEqual(C.__orig_bases__, (List[T][U][V],)) self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) + def test_extended_generic_rules_eq(self): + T = TypeVar('T') + U = TypeVar('U') + self.assertEqual(Tuple[T, T][int], Tuple[int, int]) + self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) + with self.assertRaises(TypeError): + Tuple[T, int][()] + with self.assertRaises(TypeError): + Tuple[T, U][T, ...] + + self.assertEqual(Union[T, int][int], int) + self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) + class Base: ... + class Derived(Base): ... + self.assertEqual(Union[T, Base][Derived], Base) + with self.assertRaises(TypeError): + Union[T, int][1] + + self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) + self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) + with self.assertRaises(TypeError): + Callable[[T], U][..., int] + with self.assertRaises(TypeError): + Callable[[T], U][[], int] + + def test_extended_generic_rules_repr(self): + T = TypeVar('T') + self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''), + 'Union[Tuple, Callable]') + self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), + 'Tuple') + self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), + 'Callable[..., Union[int, NoneType]]') + self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), + 'Callable[[], List[int]]') + + def test_generic_forvard_ref(self): + def foobar(x: List[List['T']]): ... + T = TypeVar('T') + self.assertEqual(get_type_hints(foobar, globals(), locals()), {'x': List[List[T]]}) + def barfoo(x: Tuple[T, ...]): ... + self.assertIs(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) + + def test_extended_generic_rules_subclassing(self): + class T1(Tuple[T, KT]): ... + class T2(Tuple[T, ...]): ... + class C1(Callable[[T], T]): ... + class C2(Callable[..., int]): + def __call__(self): + return None + + self.assertEqual(T1.__parameters__, (T, KT)) + self.assertEqual(T1[int, str].__args__, (int, str)) + self.assertEqual(T1[int, T].__origin__, T1) + + self.assertEqual(T2.__parameters__, (T,)) + with self.assertRaises(TypeError): + T1[int] + with self.assertRaises(TypeError): + T2[int, str] + + self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') + self.assertEqual(C2.__parameters__, ()) + self.assertIsInstance(C2(), collections_abc.Callable) + self.assertIsSubclass(C2, collections_abc.Callable) + self.assertIsSubclass(C1, collections_abc.Callable) + self.assertIsInstance(T1(), tuple) + self.assertIsSubclass(T2, tuple) + self.assertIsSubclass(Tuple[int, ...], typing.Sequence) + self.assertIsSubclass(Tuple[int, ...], typing.Iterable) + + def test_fail_with_bare_union(self): + with self.assertRaises(TypeError): + List[Union] + with self.assertRaises(TypeError): + Tuple[Optional] + with self.assertRaises(TypeError): + ClassVar[ClassVar] + with self.assertRaises(TypeError): + List[ClassVar[int]] + + def test_fail_with_bare_generic(self): + T = TypeVar('T') + with self.assertRaises(TypeError): + List[Generic] + with self.assertRaises(TypeError): + Tuple[Generic[T]] + with self.assertRaises(TypeError): + List[typing._Protocol] + + def test_type_erasure_special(self): + T = TypeVar('T') + class MyTup(Tuple[T, T]): ... + self.assertIs(MyTup[int]().__class__, MyTup) + self.assertIs(MyTup[int]().__orig_class__, MyTup[int]) + class MyCall(Callable[..., T]): + def __call__(self): return None + self.assertIs(MyCall[T]().__class__, MyCall) + self.assertIs(MyCall[T]().__orig_class__, MyCall[T]) + class MyDict(typing.Dict[T, T]): ... + self.assertIs(MyDict[int]().__class__, MyDict) + self.assertIs(MyDict[int]().__orig_class__, MyDict[int]) + class MyDef(typing.DefaultDict[str, T]): ... + self.assertIs(MyDef[int]().__class__, MyDef) + self.assertIs(MyDef[int]().__orig_class__, MyDef[int]) + + def test_all_repr_eq_any(self): + objs = (getattr(typing, el) for el in typing.__all__) + for obj in objs: + self.assertNotEqual(repr(obj), '') + self.assertEqual(obj, obj) + if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: + self.assertEqual(obj[Any].__args__, (Any,)) + if isinstance(obj, type): + for base in obj.__mro__: + self.assertNotEqual(repr(base), '') + self.assertEqual(base, base) + + def test_substitution_helper(self): + T = TypeVar('T') + KT = TypeVar('KT') + VT = TypeVar('VT') + class Map(Generic[KT, VT]): + def meth(self, k: KT, v: VT): ... + StrMap = Map[str, T] + obj = StrMap[int]() + + new_args = typing._subs_tree(obj.__orig_class__) + new_annots = {k: typing._replace_arg(v, type(obj).__parameters__, new_args) + for k, v in obj.meth.__annotations__.items()} + + self.assertEqual(new_annots, {'k': str, 'v': int}) def test_pickle(self): global C # pickle wants to reference the class by name @@ -752,7 +867,7 @@ X = C[int] self.assertEqual(X.__module__, __name__) if not PY32: - self.assertEqual(X.__qualname__, 'C') + self.assertTrue(X.__qualname__.endswith('..C')) self.assertEqual(repr(X).split('.')[-1], 'C[int]') class Y(C[int]): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -333,8 +333,7 @@ def _eval_type(t, globalns, localns): if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): return t._eval_type(globalns, localns) - else: - return t + return t def _type_check(arg, msg): @@ -353,8 +352,14 @@ return type(None) if isinstance(arg, str): arg = _ForwardRef(arg) - if not isinstance(arg, (type, _TypingBase)) and not callable(arg): + if (isinstance(arg, _TypingBase) and type(arg).__name__ == '_ClassVar' or + not isinstance(arg, (type, _TypingBase)) and not callable(arg)): raise TypeError(msg + " Got %.100r." % (arg,)) + # Bare Union etc. are not valid as type arguments + if (type(arg).__name__ in ('_Union', '_Optional') + and not getattr(arg, '__origin__', None) + or isinstance(arg, TypingMeta) and _gorg(arg) in (Generic, _Protocol)): + raise TypeError("Plain %s is not valid as type argument" % arg) return arg @@ -369,10 +374,12 @@ if isinstance(obj, type) and not isinstance(obj, TypingMeta): if obj.__module__ == 'builtins': return _qualname(obj) - else: - return '%s.%s' % (obj.__module__, _qualname(obj)) - else: - return repr(obj) + return '%s.%s' % (obj.__module__, _qualname(obj)) + if obj is ...: + return('...') + if isinstance(obj, types.FunctionType): + return obj.__name__ + return repr(obj) class _Any(_FinalTypingBase, _root=True): @@ -502,7 +509,107 @@ AnyStr = TypeVar('AnyStr', bytes, str) +def _replace_arg(arg, tvars, args): + """ A helper fuunction: replace arg if it is a type variable + found in tvars with corresponding substitution from args or + with corresponding substitution sub-tree if arg is a generic type. + """ + + if tvars is None: + tvars = [] + if hasattr(arg, '_subs_tree'): + return arg._subs_tree(tvars, args) + if isinstance(arg, TypeVar): + for i, tvar in enumerate(tvars): + if arg == tvar: + return args[i] + return arg + + +def _subs_tree(cls, tvars=None, args=None): + """ Calculate substitution tree for generic cls after + replacing its type parameters with substitutions in tvars -> args (if any). + Repeat the same cyclicaly following __origin__'s. + """ + + if cls.__origin__ is None: + return cls + # Make of chain of origins (i.e. cls -> cls.__origin__) + current = cls.__origin__ + orig_chain = [] + while current.__origin__ is not None: + orig_chain.append(current) + current = current.__origin__ + # Replace type variables in __args__ if asked ... + tree_args = [] + for arg in cls.__args__: + tree_args.append(_replace_arg(arg, tvars, args)) + # ... then continue replacing down the origin chain. + for ocls in orig_chain: + new_tree_args = [] + for i, arg in enumerate(ocls.__args__): + new_tree_args.append(_replace_arg(arg, ocls.__parameters__, tree_args)) + tree_args = new_tree_args + return tree_args + + +def _remove_dups_flatten(parameters): + """ A helper for Union creation and substitution: flatten Union's + among parameters, then remove duplicates and strict subclasses. + """ + + # Flatten out Union[Union[...], ...]. + params = [] + for p in parameters: + if isinstance(p, _Union) and p.__origin__ is Union: + params.extend(p.__args__) + elif isinstance(p, tuple) and len(p) > 0 and p[0] is Union: + params.extend(p[1:]) + else: + params.append(p) + # Weed out strict duplicates, preserving the first of each occurrence. + all_params = set(params) + if len(all_params) < len(params): + new_params = [] + for t in params: + if t in all_params: + new_params.append(t) + all_params.remove(t) + params = new_params + assert not all_params, all_params + # Weed out subclasses. + # E.g. Union[int, Employee, Manager] == Union[int, Employee]. + # If object is present it will be sole survivor among proper classes. + # Never discard type variables. + # (In particular, Union[str, AnyStr] != AnyStr.) + all_params = set(params) + for t1 in params: + if not isinstance(t1, type): + continue + if any(isinstance(t2, type) and issubclass(t1, t2) + for t2 in all_params - {t1} + if not (isinstance(t2, GenericMeta) and + t2.__origin__ is not None)): + all_params.remove(t1) + return tuple(t for t in params if t in all_params) + + +def _check_generic(cls, parameters): + # Check correct count for parameters of a generic cls. + if not cls.__parameters__: + raise TypeError("%s is not a generic class" % repr(cls)) + alen = len(parameters) + elen = len(cls.__parameters__) + if alen != elen: + raise TypeError("Too %s parameters for %s; actual %s, expected %s" % + ("many" if alen > elen else "few", repr(cls), alen, elen)) + + def _tp_cache(func): + """ Caching for __getitem__ of generic types with a fallback to + original function for non-hashable arguments. + """ + cached = functools.lru_cache()(func) @functools.wraps(func) def inner(*args, **kwds): @@ -555,100 +662,100 @@ - You cannot subclass or instantiate a union. - - You cannot write Union[X][Y] (what would it mean?). - - You can use Optional[X] as a shorthand for Union[X, None]. """ - __slots__ = ('__union_params__', '__union_set_params__') - - def __new__(cls, parameters=None, *args, _root=False): - self = super().__new__(cls, parameters, *args, _root=_root) - if parameters is None: - self.__union_params__ = None - self.__union_set_params__ = None + __slots__ = ('__parameters__', '__args__', '__origin__', '__tree_hash__') + + def __new__(cls, parameters=None, origin=None, *args, _root=False): + self = super().__new__(cls, parameters, origin, *args, _root=_root) + if origin is None: + self.__parameters__ = None + self.__args__ = None + self.__origin__ = None + self.__tree_hash__ = hash(frozenset(('Union',))) return self if not isinstance(parameters, tuple): raise TypeError("Expected parameters=") - # Flatten out Union[Union[...], ...] and type-check non-Union args. - params = [] - msg = "Union[arg, ...]: each arg must be a type." - for p in parameters: - if isinstance(p, _Union): - params.extend(p.__union_params__) + if origin is Union: + parameters = _remove_dups_flatten(parameters) + # It's not a union if there's only one type left. + if len(parameters) == 1: + return parameters[0] + self.__parameters__ = _type_vars(parameters) + self.__args__ = parameters + self.__origin__ = origin + # Pre-calculate the __hash__ on instantiation. + # This improves speed for complex substitutions. + subs_tree = self._subs_tree() + if isinstance(subs_tree, tuple): + self.__tree_hash__ = hash(frozenset(subs_tree)) + else: + self.__tree_hash__ = hash(subs_tree) + return self + + def _eval_type(self, globalns, localns): + if self.__args__ is None: + return self + ev_args = tuple(_eval_type(t, globalns, localns) for t in self.__args__) + ev_origin = _eval_type(self.__origin__, globalns, localns) + if ev_args == self.__args__ and ev_origin == self.__origin__: + # Everything is already evaluated. + return self + return self.__class__(ev_args, ev_origin, _root=True) + + def _get_type_vars(self, tvars): + if self.__origin__ and self.__parameters__: + _get_type_vars(self.__parameters__, tvars) + + def __repr__(self): + if self.__origin__ is None: + return super().__repr__() + tree = self._subs_tree() + if not isinstance(tree, tuple): + return repr(tree) + return tree[0]._tree_repr(tree) + + def _tree_repr(self, tree): + arg_list = [] + for arg in tree[1:]: + if not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) else: - params.append(_type_check(p, msg)) - # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - # Weed out subclasses. - # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If object is present it will be sole survivor among proper classes. - # Never discard type variables. - # (In particular, Union[str, AnyStr] != AnyStr.) - all_params = set(params) - for t1 in params: - if not isinstance(t1, type): - continue - if any(isinstance(t2, type) and issubclass(t1, t2) - for t2 in all_params - {t1} - if not (isinstance(t2, GenericMeta) and - t2.__origin__ is not None)): - all_params.remove(t1) - # It's not a union if there's only one type left. - if len(all_params) == 1: - return all_params.pop() - self.__union_params__ = tuple(t for t in params if t in all_params) - self.__union_set_params__ = frozenset(self.__union_params__) - return self - - def _eval_type(self, globalns, localns): - p = tuple(_eval_type(t, globalns, localns) - for t in self.__union_params__) - if p == self.__union_params__: - return self - else: - return self.__class__(p, _root=True) - - def _get_type_vars(self, tvars): - if self.__union_params__: - _get_type_vars(self.__union_params__, tvars) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__union_params__: - r += '[%s]' % (', '.join(_replace_arg(t, tvars, args) - for t in self.__union_params__)) - return r + arg_list.append(arg[0]._tree_repr(arg)) + return super().__repr__() + '[%s]' % ', '.join(arg_list) @_tp_cache def __getitem__(self, parameters): - if self.__union_params__ is not None: - raise TypeError( - "Cannot subscript an existing Union. Use Union[u, t] instead.") if parameters == (): raise TypeError("Cannot take a Union of no types.") if not isinstance(parameters, tuple): parameters = (parameters,) - return self.__class__(parameters, _root=True) + if self.__origin__ is None: + msg = "Union[arg, ...]: each arg must be a type." + else: + msg = "Parameters to generic types must be types." + parameters = tuple(_type_check(p, msg) for p in parameters) + if self is not Union: + _check_generic(self, parameters) + return self.__class__(parameters, origin=self, _root=True) + + def _subs_tree(self, tvars=None, args=None): + if self is Union: + return Union # Nothing to substitute + tree_args = _subs_tree(self, tvars, args) + tree_args = _remove_dups_flatten(tree_args) + if len(tree_args) == 1: + return tree_args[0] # Union of a single type is that type + return (Union,) + tree_args def __eq__(self, other): if not isinstance(other, _Union): - return NotImplemented - return self.__union_set_params__ == other.__union_set_params__ + return self._subs_tree() == other + return self.__tree_hash__ == other.__tree_hash__ def __hash__(self): - return hash(self.__union_set_params__) + return self.__tree_hash__ def __instancecheck__(self, obj): raise TypeError("Unions cannot be used with isinstance().") @@ -677,195 +784,6 @@ Optional = _Optional(_root=True) -class _Tuple(_FinalTypingBase, _root=True): - """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. - - Example: Tuple[T1, T2] is a tuple of two elements corresponding - to type variables T1 and T2. Tuple[int, float, str] is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. - """ - - __slots__ = ('__tuple_params__', '__tuple_use_ellipsis__') - - def __init__(self, parameters=None, - use_ellipsis=False, _root=False): - self.__tuple_params__ = parameters - self.__tuple_use_ellipsis__ = use_ellipsis - - def _get_type_vars(self, tvars): - if self.__tuple_params__: - _get_type_vars(self.__tuple_params__, tvars) - - def _eval_type(self, globalns, localns): - tp = self.__tuple_params__ - if tp is None: - return self - p = tuple(_eval_type(t, globalns, localns) for t in tp) - if p == self.__tuple_params__: - return self - else: - return self.__class__(p, _root=True) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__tuple_params__ is not None: - params = [_replace_arg(p, tvars, args) for p in self.__tuple_params__] - if self.__tuple_use_ellipsis__: - params.append('...') - if not params: - params.append('()') - r += '[%s]' % ( - ', '.join(params)) - return r - - @_tp_cache - def __getitem__(self, parameters): - if self.__tuple_params__ is not None: - raise TypeError("Cannot re-parameterize %r" % (self,)) - if not isinstance(parameters, tuple): - parameters = (parameters,) - if len(parameters) == 2 and parameters[1] == Ellipsis: - parameters = parameters[:1] - use_ellipsis = True - msg = "Tuple[t, ...]: t must be a type." - else: - use_ellipsis = False - msg = "Tuple[t0, t1, ...]: each t must be a type." - parameters = tuple(_type_check(p, msg) for p in parameters) - return self.__class__(parameters, - use_ellipsis=use_ellipsis, _root=True) - - def __eq__(self, other): - if not isinstance(other, _Tuple): - return NotImplemented - return (self.__tuple_params__ == other.__tuple_params__ and - self.__tuple_use_ellipsis__ == other.__tuple_use_ellipsis__) - - def __hash__(self): - return hash((self.__tuple_params__, self.__tuple_use_ellipsis__)) - - def __instancecheck__(self, obj): - if self.__tuple_params__ == None: - return isinstance(obj, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__tuple_params__ == None: - return issubclass(cls, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with issubclass().") - - -Tuple = _Tuple(_root=True) - - -class _Callable(_FinalTypingBase, _root=True): - """Callable type; Callable[[int], str] is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - """ - - __slots__ = ('__args__', '__result__') - - def __init__(self, args=None, result=None, _root=False): - if args is None and result is None: - pass - else: - if args is not Ellipsis: - if not isinstance(args, list): - raise TypeError("Callable[args, result]: " - "args must be a list." - " Got %.100r." % (args,)) - msg = "Callable[[arg, ...], result]: each arg must be a type." - args = tuple(_type_check(arg, msg) for arg in args) - msg = "Callable[args, result]: result must be a type." - result = _type_check(result, msg) - self.__args__ = args - self.__result__ = result - - def _get_type_vars(self, tvars): - if self.__args__ and self.__args__ is not Ellipsis: - _get_type_vars(self.__args__, tvars) - if self.__result__: - _get_type_vars([self.__result__], tvars) - - def _eval_type(self, globalns, localns): - if self.__args__ is None and self.__result__ is None: - return self - if self.__args__ is Ellipsis: - args = self.__args__ - else: - args = [_eval_type(t, globalns, localns) for t in self.__args__] - result = _eval_type(self.__result__, globalns, localns) - if args == self.__args__ and result == self.__result__: - return self - else: - return self.__class__(args, result, _root=True) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__args__ is not None or self.__result__ is not None: - if self.__args__ is Ellipsis: - args_r = '...' - else: - args_r = '[%s]' % ', '.join(_replace_arg(t, tvars, args) - for t in self.__args__) - r += '[%s, %s]' % (args_r, _replace_arg(self.__result__, tvars, args)) - return r - - def __getitem__(self, parameters): - if self.__args__ is not None or self.__result__ is not None: - raise TypeError("This Callable type is already parameterized.") - if not isinstance(parameters, tuple) or len(parameters) != 2: - raise TypeError( - "Callable must be used as Callable[[arg, ...], result].") - args, result = parameters - return self.__class__(args, result, _root=True) - - def __eq__(self, other): - if not isinstance(other, _Callable): - return NotImplemented - return (self.__args__ == other.__args__ and - self.__result__ == other.__result__) - - def __hash__(self): - return hash(self.__args__) ^ hash(self.__result__) - - def __instancecheck__(self, obj): - # For unparametrized Callable we allow this, because - # typing.Callable should be equivalent to - # collections.abc.Callable. - if self.__args__ is None and self.__result__ is None: - return isinstance(obj, collections_abc.Callable) - else: - raise TypeError("Parameterized Callable cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__args__ is None and self.__result__ is None: - return issubclass(cls, collections_abc.Callable) - else: - raise TypeError("Parameterized Callable cannot be used " - "with issubclass().") - - -Callable = _Callable(_root=True) - - def _gorg(a): """Return the farthest origin of a generic class.""" assert isinstance(a, GenericMeta) @@ -889,16 +807,6 @@ return _gorg(a) is _gorg(b) -def _replace_arg(arg, tvars, args): - if hasattr(arg, '_subs_repr'): - return arg._subs_repr(tvars, args) - if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg == tvar: - return args[i] - return _type_repr(arg) - - def _next_in_mro(cls): """Helper for Generic.__new__. @@ -1011,7 +919,11 @@ self = super().__new__(cls, name, bases, namespace, _root=True) self.__parameters__ = tvars - self.__args__ = args + # Be prepared that GenericMeta will be subclassed by TupleMeta + # and CallableMeta, those two allow ..., (), or [] in __args___. + self.__args__ = tuple(... if a is _TypingEllipsis else + () if a is _TypingEmpty else + a for a in args) if args else None self.__origin__ = origin self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). @@ -1029,55 +941,69 @@ self.__subclasshook__ = _make_subclasshook(self) if isinstance(extra, abc.ABCMeta): self._abc_registry = extra._abc_registry + + if origin and hasattr(origin, '__qualname__'): # Fix for Python 3.2. + self.__qualname__ = origin.__qualname__ + self.__tree_hash__ = hash(self._subs_tree()) if origin else hash((self.__name__,)) return self def _get_type_vars(self, tvars): if self.__origin__ and self.__parameters__: _get_type_vars(self.__parameters__, tvars) + def _eval_type(self, globalns, localns): + ev_origin = (self.__origin__._eval_type(globalns, localns) + if self.__origin__ else None) + ev_args = tuple(_eval_type(a, globalns, localns) for a + in self.__args__) if self.__args__ else None + if ev_origin == self.__origin__ and ev_args == self.__args__: + return self + return self.__class__(self.__name__, + self.__bases__, + dict(self.__dict__), + tvars=_type_vars(ev_args) if ev_args else None, + args=ev_args, + origin=ev_origin, + extra=self.__extra__, + orig_bases=self.__orig_bases__) + def __repr__(self): if self.__origin__ is None: return super().__repr__() - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - assert len(tvars) == len(args) - # Construct the chain of __origin__'s. - current = self.__origin__ - orig_chain = [] - while current.__origin__ is not None: - orig_chain.append(current) - current = current.__origin__ - # Replace type variables in __args__ if asked ... - str_args = [] - for arg in self.__args__: - str_args.append(_replace_arg(arg, tvars, args)) - # ... then continue replacing down the origin chain. - for cls in orig_chain: - new_str_args = [] - for i, arg in enumerate(cls.__args__): - new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args)) - str_args = new_str_args - return super().__repr__() + '[%s]' % ', '.join(str_args) + return self._tree_repr(self._subs_tree()) + + def _tree_repr(self, tree): + arg_list = [] + for arg in tree[1:]: + if arg == (): + arg_list.append('()') + elif not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) + else: + arg_list.append(arg[0]._tree_repr(arg)) + return super().__repr__() + '[%s]' % ', '.join(arg_list) + + def _subs_tree(self, tvars=None, args=None): + if self.__origin__ is None: + return self + tree_args = _subs_tree(self, tvars, args) + return (_gorg(self),) + tuple(tree_args) def __eq__(self, other): if not isinstance(other, GenericMeta): return NotImplemented - if self.__origin__ is not None: - return (self.__origin__ is other.__origin__ and - self.__args__ == other.__args__ and - self.__parameters__ == other.__parameters__) - else: + if self.__origin__ is None or other.__origin__ is None: return self is other + return self.__tree_hash__ == other.__tree_hash__ def __hash__(self): - return hash((self.__name__, self.__parameters__)) + return self.__tree_hash__ @_tp_cache def __getitem__(self, params): if not isinstance(params, tuple): params = (params,) - if not params: + if not params and not _gorg(self) is Tuple: raise TypeError( "Parameter list to %s[...] cannot be empty" % _qualname(self)) msg = "Parameters to generic types must be types." @@ -1092,6 +1018,9 @@ "Parameters to Generic[...] must all be unique") tvars = params args = params + elif self in (Tuple, Callable): + tvars = _type_vars(params) + args = params elif self is _Protocol: # _Protocol is internal, don't check anything. tvars = params @@ -1102,14 +1031,7 @@ repr(self)) else: # Subscripting a regular Generic subclass. - if not self.__parameters__: - raise TypeError("%s is not a generic class" % repr(self)) - alen = len(params) - elen = len(self.__parameters__) - if alen != elen: - raise TypeError( - "Too %s parameters for %s; actual %s, expected %s" % - ("many" if alen > elen else "few", repr(self), alen, elen)) + _check_generic(self, params) tvars = _type_vars(params) args = params return self.__class__(self.__name__, @@ -1134,6 +1056,22 @@ Generic = None +def _generic_new(base_cls, cls, *args, **kwds): + # Assure type is erased on instantiation, + # but attempt to store it in __orig_class__ + if cls.__origin__ is None: + return base_cls.__new__(cls) + else: + origin = _gorg(cls) + obj = base_cls.__new__(origin) + try: + obj.__orig_class__ = cls + except AttributeError: + pass + obj.__init__(*args, **kwds) + return obj + + class Generic(metaclass=GenericMeta): """Abstract base class for generic types. @@ -1158,17 +1096,154 @@ __slots__ = () def __new__(cls, *args, **kwds): - if cls.__origin__ is None: - return cls.__next_in_mro__.__new__(cls) + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) + + +class _TypingEmpty: + """Placeholder for () or []. Used by TupleMeta and CallableMeta + to allow empy list/tuple in specific places, without allowing them + to sneak in where prohibited. + """ + + +class _TypingEllipsis: + """Ditto for ...""" + + +class TupleMeta(GenericMeta): + """Metaclass for Tuple""" + + @_tp_cache + def __getitem__(self, parameters): + if self.__origin__ is not None or not _geqv(self, Tuple): + # Normal generic rules apply if this is not the first subscription + # or a subscription of a subclass. + return super().__getitem__(parameters) + if parameters == (): + return super().__getitem__((_TypingEmpty,)) + if not isinstance(parameters, tuple): + parameters = (parameters,) + if len(parameters) == 2 and parameters[1] is ...: + msg = "Tuple[t, ...]: t must be a type." + p = _type_check(parameters[0], msg) + return super().__getitem__((p, _TypingEllipsis)) + msg = "Tuple[t0, t1, ...]: each t must be a type." + parameters = tuple(_type_check(p, msg) for p in parameters) + return super().__getitem__(parameters) + + def __instancecheck__(self, obj): + if self.__args__ == None: + return isinstance(obj, tuple) + raise TypeError("Parameterized Tuple cannot be used " + "with isinstance().") + + def __subclasscheck__(self, cls): + if self.__args__ == None: + return issubclass(cls, tuple) + raise TypeError("Parameterized Tuple cannot be used " + "with issubclass().") + + +class Tuple(tuple, extra=tuple, metaclass=TupleMeta): + """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. + + Example: Tuple[T1, T2] is a tuple of two elements corresponding + to type variables T1 and T2. Tuple[int, float, str] is a tuple + of an int, a float and a string. + + To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. + """ + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Tuple): + raise TypeError("Type Tuple cannot be instantiated; " + "use tuple() instead") + return _generic_new(tuple, cls, *args, **kwds) + + +class CallableMeta(GenericMeta): + """ Metaclass for Callable.""" + + def __repr__(self): + if self.__origin__ is None: + return super().__repr__() + return self._tree_repr(self._subs_tree()) + + def _tree_repr(self, tree): + if _gorg(self) is not Callable: + return super()._tree_repr(tree) + # For actual Callable (not its subclass) we override + # super()._tree_repr() for nice formatting. + arg_list = [] + for arg in tree[1:]: + if arg == (): + arg_list.append('[]') + elif not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) + else: + arg_list.append(arg[0]._tree_repr(arg)) + if len(arg_list) == 2: + return repr(tree[0]) + '[%s]' % ', '.join(arg_list) + return (repr(tree[0]) + + '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1])) + + def __getitem__(self, parameters): + """ A thin wrapper around __getitem_inner__ to provide the latter + with hashable arguments to improve speed. + """ + + if self.__origin__ is not None or not _geqv(self, Callable): + return super().__getitem__(parameters) + if not isinstance(parameters, tuple) or len(parameters) != 2: + raise TypeError("Callable must be used as " + "Callable[[arg, ...], result].") + args, result = parameters + if args is ...: + parameters = (..., result) + elif args == []: + parameters = ((), result) else: - origin = _gorg(cls) - obj = cls.__next_in_mro__.__new__(origin) - try: - obj.__orig_class__ = cls - except AttributeError: - pass - obj.__init__(*args, **kwds) - return obj + if not isinstance(args, list): + raise TypeError("Callable[args, result]: args must be a list." + " Got %.100r." % (args,)) + parameters = tuple(args) + (result,) + return self.__getitem_inner__(parameters) + + @_tp_cache + def __getitem_inner__(self, parameters): + *args, result = parameters + msg = "Callable[args, result]: result must be a type." + result = _type_check(result, msg) + if args == [...,]: + return super().__getitem__((_TypingEllipsis, result)) + if args == [(),]: + return super().__getitem__((_TypingEmpty, result)) + msg = "Callable[[arg, ...], result]: each arg must be a type." + args = tuple(_type_check(arg, msg) for arg in args) + parameters = args + (result,) + return super().__getitem__(parameters) + + +class Callable(extra=collections_abc.Callable, metaclass = CallableMeta): + """Callable type; Callable[[int], str] is a function of (int) -> str. + + The subscription syntax must always be used with exactly two + values: the argument list and the return type. The argument list + must be a list of types; the return type must be a single type. + + There is no syntax to indicate optional or keyword arguments, + such function types are rarely used as callback types. + """ + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Callable): + raise TypeError("Type Callable cannot be instantiated; " + "use a non-abstract subclass instead") + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) class _ClassVar(_FinalTypingBase, _root=True): @@ -1208,17 +1283,10 @@ return self return type(self)(new_tp, _root=True) - def _get_type_vars(self, tvars): - if self.__type__: - _get_type_vars([self.__type__], tvars) - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(_replace_arg(self.__type__, tvars, args)) + r += '[{}]'.format(_type_repr(self.__type__)) return r def __hash__(self): @@ -1231,6 +1299,7 @@ return self.__type__ == other.__type__ return self is other + ClassVar = _ClassVar(_root=True) @@ -1533,6 +1602,7 @@ attr != '__origin__' and attr != '__orig_bases__' and attr != '__extra__' and + attr != '__tree_hash__' and attr != '__module__'): attrs.add(attr) @@ -1723,7 +1793,7 @@ if _geqv(cls, List): raise TypeError("Type List cannot be instantiated; " "use list() instead") - return list.__new__(cls, *args, **kwds) + return _generic_new(list, cls, *args, **kwds) class Set(set, MutableSet[T], extra=set): @@ -1734,7 +1804,7 @@ if _geqv(cls, Set): raise TypeError("Type Set cannot be instantiated; " "use set() instead") - return set.__new__(cls, *args, **kwds) + return _generic_new(set, cls, *args, **kwds) class FrozenSet(frozenset, AbstractSet[T_co], extra=frozenset): @@ -1744,7 +1814,7 @@ if _geqv(cls, FrozenSet): raise TypeError("Type FrozenSet cannot be instantiated; " "use frozenset() instead") - return frozenset.__new__(cls, *args, **kwds) + return _generic_new(frozenset, cls, *args, **kwds) class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView): @@ -1781,7 +1851,7 @@ if _geqv(cls, Dict): raise TypeError("Type Dict cannot be instantiated; " "use dict() instead") - return dict.__new__(cls, *args, **kwds) + return _generic_new(dict, cls, *args, **kwds) class DefaultDict(collections.defaultdict, MutableMapping[KT, VT], extra=collections.defaultdict): @@ -1792,7 +1862,7 @@ if _geqv(cls, DefaultDict): raise TypeError("Type DefaultDict cannot be instantiated; " "use collections.defaultdict() instead") - return collections.defaultdict.__new__(cls, *args, **kwds) + return _generic_new(collections.defaultdict, cls, *args, **kwds) # Determine what base class to use for Generator. if hasattr(collections_abc, 'Generator'): @@ -1811,7 +1881,7 @@ if _geqv(cls, Generator): raise TypeError("Type Generator cannot be instantiated; " "create a subclass instead") - return super().__new__(cls, *args, **kwds) + return _generic_new(_G_base, cls, *args, **kwds) # Internal type variable used for Type[]. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:55:13 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 15:55:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NTU2?= =?utf-8?q?=3A_updates_to_typing=2Epy?= Message-ID: <20161029155513.31769.84279.34F89DD3@psf.io> https://hg.python.org/cpython/rev/a47b07d0aba0 changeset: 104795:a47b07d0aba0 branch: 3.5 parent: 104790:4b2679a06ace user: Guido van Rossum date: Sat Oct 29 08:54:56 2016 -0700 summary: Issue #28556: updates to typing.py files: Lib/test/test_typing.py | 157 +++++- Lib/typing.py | 754 +++++++++++++++------------ 2 files changed, 548 insertions(+), 363 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -142,8 +142,9 @@ self.assertEqual(Union[X, X], X) self.assertNotEqual(Union[X, int], Union[X]) self.assertNotEqual(Union[X, int], Union[int]) - self.assertEqual(Union[X, int].__union_params__, (X, int)) - self.assertEqual(Union[X, int].__union_set_params__, {X, int}) + self.assertEqual(Union[X, int].__args__, (X, int)) + self.assertEqual(Union[X, int].__parameters__, (X,)) + self.assertIs(Union[X, int].__origin__, Union) def test_union_constrained(self): A = TypeVar('A', str, bytes) @@ -312,8 +313,6 @@ def test_basics(self): with self.assertRaises(TypeError): - issubclass(Tuple[int, str], Tuple) - with self.assertRaises(TypeError): issubclass(Tuple, Tuple[int, str]) with self.assertRaises(TypeError): issubclass(tuple, Tuple[int, str]) @@ -367,22 +366,6 @@ self.assertNotEqual(Callable[[int], int], Callable[[], int]) self.assertNotEqual(Callable[[int], int], Callable) - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - - class C(Callable): - pass - - with self.assertRaises(TypeError): - - class C(type(Callable)): - pass - - with self.assertRaises(TypeError): - - class C(Callable[[int], int]): - pass - def test_cannot_instantiate(self): with self.assertRaises(TypeError): Callable() @@ -710,6 +693,138 @@ self.assertEqual(C.__orig_bases__, (List[T][U][V],)) self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) + def test_extended_generic_rules_eq(self): + T = TypeVar('T') + U = TypeVar('U') + self.assertEqual(Tuple[T, T][int], Tuple[int, int]) + self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) + with self.assertRaises(TypeError): + Tuple[T, int][()] + with self.assertRaises(TypeError): + Tuple[T, U][T, ...] + + self.assertEqual(Union[T, int][int], int) + self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) + class Base: ... + class Derived(Base): ... + self.assertEqual(Union[T, Base][Derived], Base) + with self.assertRaises(TypeError): + Union[T, int][1] + + self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) + self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) + with self.assertRaises(TypeError): + Callable[[T], U][..., int] + with self.assertRaises(TypeError): + Callable[[T], U][[], int] + + def test_extended_generic_rules_repr(self): + T = TypeVar('T') + self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''), + 'Union[Tuple, Callable]') + self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), + 'Tuple') + self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), + 'Callable[..., Union[int, NoneType]]') + self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), + 'Callable[[], List[int]]') + + def test_generic_forvard_ref(self): + def foobar(x: List[List['T']]): ... + T = TypeVar('T') + self.assertEqual(get_type_hints(foobar, globals(), locals()), {'x': List[List[T]]}) + def barfoo(x: Tuple[T, ...]): ... + self.assertIs(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) + + def test_extended_generic_rules_subclassing(self): + class T1(Tuple[T, KT]): ... + class T2(Tuple[T, ...]): ... + class C1(Callable[[T], T]): ... + class C2(Callable[..., int]): + def __call__(self): + return None + + self.assertEqual(T1.__parameters__, (T, KT)) + self.assertEqual(T1[int, str].__args__, (int, str)) + self.assertEqual(T1[int, T].__origin__, T1) + + self.assertEqual(T2.__parameters__, (T,)) + with self.assertRaises(TypeError): + T1[int] + with self.assertRaises(TypeError): + T2[int, str] + + self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') + self.assertEqual(C2.__parameters__, ()) + self.assertIsInstance(C2(), collections_abc.Callable) + self.assertIsSubclass(C2, collections_abc.Callable) + self.assertIsSubclass(C1, collections_abc.Callable) + self.assertIsInstance(T1(), tuple) + self.assertIsSubclass(T2, tuple) + self.assertIsSubclass(Tuple[int, ...], typing.Sequence) + self.assertIsSubclass(Tuple[int, ...], typing.Iterable) + + def test_fail_with_bare_union(self): + with self.assertRaises(TypeError): + List[Union] + with self.assertRaises(TypeError): + Tuple[Optional] + with self.assertRaises(TypeError): + ClassVar[ClassVar] + with self.assertRaises(TypeError): + List[ClassVar[int]] + + def test_fail_with_bare_generic(self): + T = TypeVar('T') + with self.assertRaises(TypeError): + List[Generic] + with self.assertRaises(TypeError): + Tuple[Generic[T]] + with self.assertRaises(TypeError): + List[typing._Protocol] + + def test_type_erasure_special(self): + T = TypeVar('T') + class MyTup(Tuple[T, T]): ... + self.assertIs(MyTup[int]().__class__, MyTup) + self.assertIs(MyTup[int]().__orig_class__, MyTup[int]) + class MyCall(Callable[..., T]): + def __call__(self): return None + self.assertIs(MyCall[T]().__class__, MyCall) + self.assertIs(MyCall[T]().__orig_class__, MyCall[T]) + class MyDict(typing.Dict[T, T]): ... + self.assertIs(MyDict[int]().__class__, MyDict) + self.assertIs(MyDict[int]().__orig_class__, MyDict[int]) + class MyDef(typing.DefaultDict[str, T]): ... + self.assertIs(MyDef[int]().__class__, MyDef) + self.assertIs(MyDef[int]().__orig_class__, MyDef[int]) + + def test_all_repr_eq_any(self): + objs = (getattr(typing, el) for el in typing.__all__) + for obj in objs: + self.assertNotEqual(repr(obj), '') + self.assertEqual(obj, obj) + if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: + self.assertEqual(obj[Any].__args__, (Any,)) + if isinstance(obj, type): + for base in obj.__mro__: + self.assertNotEqual(repr(base), '') + self.assertEqual(base, base) + + def test_substitution_helper(self): + T = TypeVar('T') + KT = TypeVar('KT') + VT = TypeVar('VT') + class Map(Generic[KT, VT]): + def meth(self, k: KT, v: VT): ... + StrMap = Map[str, T] + obj = StrMap[int]() + + new_args = typing._subs_tree(obj.__orig_class__) + new_annots = {k: typing._replace_arg(v, type(obj).__parameters__, new_args) + for k, v in obj.meth.__annotations__.items()} + + self.assertEqual(new_annots, {'k': str, 'v': int}) def test_pickle(self): global C # pickle wants to reference the class by name @@ -752,7 +867,7 @@ X = C[int] self.assertEqual(X.__module__, __name__) if not PY32: - self.assertEqual(X.__qualname__, 'C') + self.assertTrue(X.__qualname__.endswith('..C')) self.assertEqual(repr(X).split('.')[-1], 'C[int]') class Y(C[int]): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -333,8 +333,7 @@ def _eval_type(t, globalns, localns): if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): return t._eval_type(globalns, localns) - else: - return t + return t def _type_check(arg, msg): @@ -353,8 +352,14 @@ return type(None) if isinstance(arg, str): arg = _ForwardRef(arg) - if not isinstance(arg, (type, _TypingBase)) and not callable(arg): + if (isinstance(arg, _TypingBase) and type(arg).__name__ == '_ClassVar' or + not isinstance(arg, (type, _TypingBase)) and not callable(arg)): raise TypeError(msg + " Got %.100r." % (arg,)) + # Bare Union etc. are not valid as type arguments + if (type(arg).__name__ in ('_Union', '_Optional') + and not getattr(arg, '__origin__', None) + or isinstance(arg, TypingMeta) and _gorg(arg) in (Generic, _Protocol)): + raise TypeError("Plain %s is not valid as type argument" % arg) return arg @@ -369,10 +374,12 @@ if isinstance(obj, type) and not isinstance(obj, TypingMeta): if obj.__module__ == 'builtins': return _qualname(obj) - else: - return '%s.%s' % (obj.__module__, _qualname(obj)) - else: - return repr(obj) + return '%s.%s' % (obj.__module__, _qualname(obj)) + if obj is ...: + return('...') + if isinstance(obj, types.FunctionType): + return obj.__name__ + return repr(obj) class _Any(_FinalTypingBase, _root=True): @@ -502,7 +509,107 @@ AnyStr = TypeVar('AnyStr', bytes, str) +def _replace_arg(arg, tvars, args): + """ A helper fuunction: replace arg if it is a type variable + found in tvars with corresponding substitution from args or + with corresponding substitution sub-tree if arg is a generic type. + """ + + if tvars is None: + tvars = [] + if hasattr(arg, '_subs_tree'): + return arg._subs_tree(tvars, args) + if isinstance(arg, TypeVar): + for i, tvar in enumerate(tvars): + if arg == tvar: + return args[i] + return arg + + +def _subs_tree(cls, tvars=None, args=None): + """ Calculate substitution tree for generic cls after + replacing its type parameters with substitutions in tvars -> args (if any). + Repeat the same cyclicaly following __origin__'s. + """ + + if cls.__origin__ is None: + return cls + # Make of chain of origins (i.e. cls -> cls.__origin__) + current = cls.__origin__ + orig_chain = [] + while current.__origin__ is not None: + orig_chain.append(current) + current = current.__origin__ + # Replace type variables in __args__ if asked ... + tree_args = [] + for arg in cls.__args__: + tree_args.append(_replace_arg(arg, tvars, args)) + # ... then continue replacing down the origin chain. + for ocls in orig_chain: + new_tree_args = [] + for i, arg in enumerate(ocls.__args__): + new_tree_args.append(_replace_arg(arg, ocls.__parameters__, tree_args)) + tree_args = new_tree_args + return tree_args + + +def _remove_dups_flatten(parameters): + """ A helper for Union creation and substitution: flatten Union's + among parameters, then remove duplicates and strict subclasses. + """ + + # Flatten out Union[Union[...], ...]. + params = [] + for p in parameters: + if isinstance(p, _Union) and p.__origin__ is Union: + params.extend(p.__args__) + elif isinstance(p, tuple) and len(p) > 0 and p[0] is Union: + params.extend(p[1:]) + else: + params.append(p) + # Weed out strict duplicates, preserving the first of each occurrence. + all_params = set(params) + if len(all_params) < len(params): + new_params = [] + for t in params: + if t in all_params: + new_params.append(t) + all_params.remove(t) + params = new_params + assert not all_params, all_params + # Weed out subclasses. + # E.g. Union[int, Employee, Manager] == Union[int, Employee]. + # If object is present it will be sole survivor among proper classes. + # Never discard type variables. + # (In particular, Union[str, AnyStr] != AnyStr.) + all_params = set(params) + for t1 in params: + if not isinstance(t1, type): + continue + if any(isinstance(t2, type) and issubclass(t1, t2) + for t2 in all_params - {t1} + if not (isinstance(t2, GenericMeta) and + t2.__origin__ is not None)): + all_params.remove(t1) + return tuple(t for t in params if t in all_params) + + +def _check_generic(cls, parameters): + # Check correct count for parameters of a generic cls. + if not cls.__parameters__: + raise TypeError("%s is not a generic class" % repr(cls)) + alen = len(parameters) + elen = len(cls.__parameters__) + if alen != elen: + raise TypeError("Too %s parameters for %s; actual %s, expected %s" % + ("many" if alen > elen else "few", repr(cls), alen, elen)) + + def _tp_cache(func): + """ Caching for __getitem__ of generic types with a fallback to + original function for non-hashable arguments. + """ + cached = functools.lru_cache()(func) @functools.wraps(func) def inner(*args, **kwds): @@ -555,100 +662,100 @@ - You cannot subclass or instantiate a union. - - You cannot write Union[X][Y] (what would it mean?). - - You can use Optional[X] as a shorthand for Union[X, None]. """ - __slots__ = ('__union_params__', '__union_set_params__') - - def __new__(cls, parameters=None, *args, _root=False): - self = super().__new__(cls, parameters, *args, _root=_root) - if parameters is None: - self.__union_params__ = None - self.__union_set_params__ = None + __slots__ = ('__parameters__', '__args__', '__origin__', '__tree_hash__') + + def __new__(cls, parameters=None, origin=None, *args, _root=False): + self = super().__new__(cls, parameters, origin, *args, _root=_root) + if origin is None: + self.__parameters__ = None + self.__args__ = None + self.__origin__ = None + self.__tree_hash__ = hash(frozenset(('Union',))) return self if not isinstance(parameters, tuple): raise TypeError("Expected parameters=") - # Flatten out Union[Union[...], ...] and type-check non-Union args. - params = [] - msg = "Union[arg, ...]: each arg must be a type." - for p in parameters: - if isinstance(p, _Union): - params.extend(p.__union_params__) + if origin is Union: + parameters = _remove_dups_flatten(parameters) + # It's not a union if there's only one type left. + if len(parameters) == 1: + return parameters[0] + self.__parameters__ = _type_vars(parameters) + self.__args__ = parameters + self.__origin__ = origin + # Pre-calculate the __hash__ on instantiation. + # This improves speed for complex substitutions. + subs_tree = self._subs_tree() + if isinstance(subs_tree, tuple): + self.__tree_hash__ = hash(frozenset(subs_tree)) + else: + self.__tree_hash__ = hash(subs_tree) + return self + + def _eval_type(self, globalns, localns): + if self.__args__ is None: + return self + ev_args = tuple(_eval_type(t, globalns, localns) for t in self.__args__) + ev_origin = _eval_type(self.__origin__, globalns, localns) + if ev_args == self.__args__ and ev_origin == self.__origin__: + # Everything is already evaluated. + return self + return self.__class__(ev_args, ev_origin, _root=True) + + def _get_type_vars(self, tvars): + if self.__origin__ and self.__parameters__: + _get_type_vars(self.__parameters__, tvars) + + def __repr__(self): + if self.__origin__ is None: + return super().__repr__() + tree = self._subs_tree() + if not isinstance(tree, tuple): + return repr(tree) + return tree[0]._tree_repr(tree) + + def _tree_repr(self, tree): + arg_list = [] + for arg in tree[1:]: + if not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) else: - params.append(_type_check(p, msg)) - # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - # Weed out subclasses. - # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If object is present it will be sole survivor among proper classes. - # Never discard type variables. - # (In particular, Union[str, AnyStr] != AnyStr.) - all_params = set(params) - for t1 in params: - if not isinstance(t1, type): - continue - if any(isinstance(t2, type) and issubclass(t1, t2) - for t2 in all_params - {t1} - if not (isinstance(t2, GenericMeta) and - t2.__origin__ is not None)): - all_params.remove(t1) - # It's not a union if there's only one type left. - if len(all_params) == 1: - return all_params.pop() - self.__union_params__ = tuple(t for t in params if t in all_params) - self.__union_set_params__ = frozenset(self.__union_params__) - return self - - def _eval_type(self, globalns, localns): - p = tuple(_eval_type(t, globalns, localns) - for t in self.__union_params__) - if p == self.__union_params__: - return self - else: - return self.__class__(p, _root=True) - - def _get_type_vars(self, tvars): - if self.__union_params__: - _get_type_vars(self.__union_params__, tvars) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__union_params__: - r += '[%s]' % (', '.join(_replace_arg(t, tvars, args) - for t in self.__union_params__)) - return r + arg_list.append(arg[0]._tree_repr(arg)) + return super().__repr__() + '[%s]' % ', '.join(arg_list) @_tp_cache def __getitem__(self, parameters): - if self.__union_params__ is not None: - raise TypeError( - "Cannot subscript an existing Union. Use Union[u, t] instead.") if parameters == (): raise TypeError("Cannot take a Union of no types.") if not isinstance(parameters, tuple): parameters = (parameters,) - return self.__class__(parameters, _root=True) + if self.__origin__ is None: + msg = "Union[arg, ...]: each arg must be a type." + else: + msg = "Parameters to generic types must be types." + parameters = tuple(_type_check(p, msg) for p in parameters) + if self is not Union: + _check_generic(self, parameters) + return self.__class__(parameters, origin=self, _root=True) + + def _subs_tree(self, tvars=None, args=None): + if self is Union: + return Union # Nothing to substitute + tree_args = _subs_tree(self, tvars, args) + tree_args = _remove_dups_flatten(tree_args) + if len(tree_args) == 1: + return tree_args[0] # Union of a single type is that type + return (Union,) + tree_args def __eq__(self, other): if not isinstance(other, _Union): - return NotImplemented - return self.__union_set_params__ == other.__union_set_params__ + return self._subs_tree() == other + return self.__tree_hash__ == other.__tree_hash__ def __hash__(self): - return hash(self.__union_set_params__) + return self.__tree_hash__ def __instancecheck__(self, obj): raise TypeError("Unions cannot be used with isinstance().") @@ -677,195 +784,6 @@ Optional = _Optional(_root=True) -class _Tuple(_FinalTypingBase, _root=True): - """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. - - Example: Tuple[T1, T2] is a tuple of two elements corresponding - to type variables T1 and T2. Tuple[int, float, str] is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. - """ - - __slots__ = ('__tuple_params__', '__tuple_use_ellipsis__') - - def __init__(self, parameters=None, - use_ellipsis=False, _root=False): - self.__tuple_params__ = parameters - self.__tuple_use_ellipsis__ = use_ellipsis - - def _get_type_vars(self, tvars): - if self.__tuple_params__: - _get_type_vars(self.__tuple_params__, tvars) - - def _eval_type(self, globalns, localns): - tp = self.__tuple_params__ - if tp is None: - return self - p = tuple(_eval_type(t, globalns, localns) for t in tp) - if p == self.__tuple_params__: - return self - else: - return self.__class__(p, _root=True) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__tuple_params__ is not None: - params = [_replace_arg(p, tvars, args) for p in self.__tuple_params__] - if self.__tuple_use_ellipsis__: - params.append('...') - if not params: - params.append('()') - r += '[%s]' % ( - ', '.join(params)) - return r - - @_tp_cache - def __getitem__(self, parameters): - if self.__tuple_params__ is not None: - raise TypeError("Cannot re-parameterize %r" % (self,)) - if not isinstance(parameters, tuple): - parameters = (parameters,) - if len(parameters) == 2 and parameters[1] == Ellipsis: - parameters = parameters[:1] - use_ellipsis = True - msg = "Tuple[t, ...]: t must be a type." - else: - use_ellipsis = False - msg = "Tuple[t0, t1, ...]: each t must be a type." - parameters = tuple(_type_check(p, msg) for p in parameters) - return self.__class__(parameters, - use_ellipsis=use_ellipsis, _root=True) - - def __eq__(self, other): - if not isinstance(other, _Tuple): - return NotImplemented - return (self.__tuple_params__ == other.__tuple_params__ and - self.__tuple_use_ellipsis__ == other.__tuple_use_ellipsis__) - - def __hash__(self): - return hash((self.__tuple_params__, self.__tuple_use_ellipsis__)) - - def __instancecheck__(self, obj): - if self.__tuple_params__ == None: - return isinstance(obj, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__tuple_params__ == None: - return issubclass(cls, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with issubclass().") - - -Tuple = _Tuple(_root=True) - - -class _Callable(_FinalTypingBase, _root=True): - """Callable type; Callable[[int], str] is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - """ - - __slots__ = ('__args__', '__result__') - - def __init__(self, args=None, result=None, _root=False): - if args is None and result is None: - pass - else: - if args is not Ellipsis: - if not isinstance(args, list): - raise TypeError("Callable[args, result]: " - "args must be a list." - " Got %.100r." % (args,)) - msg = "Callable[[arg, ...], result]: each arg must be a type." - args = tuple(_type_check(arg, msg) for arg in args) - msg = "Callable[args, result]: result must be a type." - result = _type_check(result, msg) - self.__args__ = args - self.__result__ = result - - def _get_type_vars(self, tvars): - if self.__args__ and self.__args__ is not Ellipsis: - _get_type_vars(self.__args__, tvars) - if self.__result__: - _get_type_vars([self.__result__], tvars) - - def _eval_type(self, globalns, localns): - if self.__args__ is None and self.__result__ is None: - return self - if self.__args__ is Ellipsis: - args = self.__args__ - else: - args = [_eval_type(t, globalns, localns) for t in self.__args__] - result = _eval_type(self.__result__, globalns, localns) - if args == self.__args__ and result == self.__result__: - return self - else: - return self.__class__(args, result, _root=True) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__args__ is not None or self.__result__ is not None: - if self.__args__ is Ellipsis: - args_r = '...' - else: - args_r = '[%s]' % ', '.join(_replace_arg(t, tvars, args) - for t in self.__args__) - r += '[%s, %s]' % (args_r, _replace_arg(self.__result__, tvars, args)) - return r - - def __getitem__(self, parameters): - if self.__args__ is not None or self.__result__ is not None: - raise TypeError("This Callable type is already parameterized.") - if not isinstance(parameters, tuple) or len(parameters) != 2: - raise TypeError( - "Callable must be used as Callable[[arg, ...], result].") - args, result = parameters - return self.__class__(args, result, _root=True) - - def __eq__(self, other): - if not isinstance(other, _Callable): - return NotImplemented - return (self.__args__ == other.__args__ and - self.__result__ == other.__result__) - - def __hash__(self): - return hash(self.__args__) ^ hash(self.__result__) - - def __instancecheck__(self, obj): - # For unparametrized Callable we allow this, because - # typing.Callable should be equivalent to - # collections.abc.Callable. - if self.__args__ is None and self.__result__ is None: - return isinstance(obj, collections_abc.Callable) - else: - raise TypeError("Parameterized Callable cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__args__ is None and self.__result__ is None: - return issubclass(cls, collections_abc.Callable) - else: - raise TypeError("Parameterized Callable cannot be used " - "with issubclass().") - - -Callable = _Callable(_root=True) - - def _gorg(a): """Return the farthest origin of a generic class.""" assert isinstance(a, GenericMeta) @@ -889,16 +807,6 @@ return _gorg(a) is _gorg(b) -def _replace_arg(arg, tvars, args): - if hasattr(arg, '_subs_repr'): - return arg._subs_repr(tvars, args) - if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg == tvar: - return args[i] - return _type_repr(arg) - - def _next_in_mro(cls): """Helper for Generic.__new__. @@ -1011,7 +919,11 @@ self = super().__new__(cls, name, bases, namespace, _root=True) self.__parameters__ = tvars - self.__args__ = args + # Be prepared that GenericMeta will be subclassed by TupleMeta + # and CallableMeta, those two allow ..., (), or [] in __args___. + self.__args__ = tuple(... if a is _TypingEllipsis else + () if a is _TypingEmpty else + a for a in args) if args else None self.__origin__ = origin self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). @@ -1029,55 +941,69 @@ self.__subclasshook__ = _make_subclasshook(self) if isinstance(extra, abc.ABCMeta): self._abc_registry = extra._abc_registry + + if origin and hasattr(origin, '__qualname__'): # Fix for Python 3.2. + self.__qualname__ = origin.__qualname__ + self.__tree_hash__ = hash(self._subs_tree()) if origin else hash((self.__name__,)) return self def _get_type_vars(self, tvars): if self.__origin__ and self.__parameters__: _get_type_vars(self.__parameters__, tvars) + def _eval_type(self, globalns, localns): + ev_origin = (self.__origin__._eval_type(globalns, localns) + if self.__origin__ else None) + ev_args = tuple(_eval_type(a, globalns, localns) for a + in self.__args__) if self.__args__ else None + if ev_origin == self.__origin__ and ev_args == self.__args__: + return self + return self.__class__(self.__name__, + self.__bases__, + dict(self.__dict__), + tvars=_type_vars(ev_args) if ev_args else None, + args=ev_args, + origin=ev_origin, + extra=self.__extra__, + orig_bases=self.__orig_bases__) + def __repr__(self): if self.__origin__ is None: return super().__repr__() - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - assert len(tvars) == len(args) - # Construct the chain of __origin__'s. - current = self.__origin__ - orig_chain = [] - while current.__origin__ is not None: - orig_chain.append(current) - current = current.__origin__ - # Replace type variables in __args__ if asked ... - str_args = [] - for arg in self.__args__: - str_args.append(_replace_arg(arg, tvars, args)) - # ... then continue replacing down the origin chain. - for cls in orig_chain: - new_str_args = [] - for i, arg in enumerate(cls.__args__): - new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args)) - str_args = new_str_args - return super().__repr__() + '[%s]' % ', '.join(str_args) + return self._tree_repr(self._subs_tree()) + + def _tree_repr(self, tree): + arg_list = [] + for arg in tree[1:]: + if arg == (): + arg_list.append('()') + elif not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) + else: + arg_list.append(arg[0]._tree_repr(arg)) + return super().__repr__() + '[%s]' % ', '.join(arg_list) + + def _subs_tree(self, tvars=None, args=None): + if self.__origin__ is None: + return self + tree_args = _subs_tree(self, tvars, args) + return (_gorg(self),) + tuple(tree_args) def __eq__(self, other): if not isinstance(other, GenericMeta): return NotImplemented - if self.__origin__ is not None: - return (self.__origin__ is other.__origin__ and - self.__args__ == other.__args__ and - self.__parameters__ == other.__parameters__) - else: + if self.__origin__ is None or other.__origin__ is None: return self is other + return self.__tree_hash__ == other.__tree_hash__ def __hash__(self): - return hash((self.__name__, self.__parameters__)) + return self.__tree_hash__ @_tp_cache def __getitem__(self, params): if not isinstance(params, tuple): params = (params,) - if not params: + if not params and not _gorg(self) is Tuple: raise TypeError( "Parameter list to %s[...] cannot be empty" % _qualname(self)) msg = "Parameters to generic types must be types." @@ -1092,6 +1018,9 @@ "Parameters to Generic[...] must all be unique") tvars = params args = params + elif self in (Tuple, Callable): + tvars = _type_vars(params) + args = params elif self is _Protocol: # _Protocol is internal, don't check anything. tvars = params @@ -1102,14 +1031,7 @@ repr(self)) else: # Subscripting a regular Generic subclass. - if not self.__parameters__: - raise TypeError("%s is not a generic class" % repr(self)) - alen = len(params) - elen = len(self.__parameters__) - if alen != elen: - raise TypeError( - "Too %s parameters for %s; actual %s, expected %s" % - ("many" if alen > elen else "few", repr(self), alen, elen)) + _check_generic(self, params) tvars = _type_vars(params) args = params return self.__class__(self.__name__, @@ -1134,6 +1056,22 @@ Generic = None +def _generic_new(base_cls, cls, *args, **kwds): + # Assure type is erased on instantiation, + # but attempt to store it in __orig_class__ + if cls.__origin__ is None: + return base_cls.__new__(cls) + else: + origin = _gorg(cls) + obj = base_cls.__new__(origin) + try: + obj.__orig_class__ = cls + except AttributeError: + pass + obj.__init__(*args, **kwds) + return obj + + class Generic(metaclass=GenericMeta): """Abstract base class for generic types. @@ -1158,17 +1096,154 @@ __slots__ = () def __new__(cls, *args, **kwds): - if cls.__origin__ is None: - return cls.__next_in_mro__.__new__(cls) + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) + + +class _TypingEmpty: + """Placeholder for () or []. Used by TupleMeta and CallableMeta + to allow empy list/tuple in specific places, without allowing them + to sneak in where prohibited. + """ + + +class _TypingEllipsis: + """Ditto for ...""" + + +class TupleMeta(GenericMeta): + """Metaclass for Tuple""" + + @_tp_cache + def __getitem__(self, parameters): + if self.__origin__ is not None or not _geqv(self, Tuple): + # Normal generic rules apply if this is not the first subscription + # or a subscription of a subclass. + return super().__getitem__(parameters) + if parameters == (): + return super().__getitem__((_TypingEmpty,)) + if not isinstance(parameters, tuple): + parameters = (parameters,) + if len(parameters) == 2 and parameters[1] is ...: + msg = "Tuple[t, ...]: t must be a type." + p = _type_check(parameters[0], msg) + return super().__getitem__((p, _TypingEllipsis)) + msg = "Tuple[t0, t1, ...]: each t must be a type." + parameters = tuple(_type_check(p, msg) for p in parameters) + return super().__getitem__(parameters) + + def __instancecheck__(self, obj): + if self.__args__ == None: + return isinstance(obj, tuple) + raise TypeError("Parameterized Tuple cannot be used " + "with isinstance().") + + def __subclasscheck__(self, cls): + if self.__args__ == None: + return issubclass(cls, tuple) + raise TypeError("Parameterized Tuple cannot be used " + "with issubclass().") + + +class Tuple(tuple, extra=tuple, metaclass=TupleMeta): + """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. + + Example: Tuple[T1, T2] is a tuple of two elements corresponding + to type variables T1 and T2. Tuple[int, float, str] is a tuple + of an int, a float and a string. + + To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. + """ + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Tuple): + raise TypeError("Type Tuple cannot be instantiated; " + "use tuple() instead") + return _generic_new(tuple, cls, *args, **kwds) + + +class CallableMeta(GenericMeta): + """ Metaclass for Callable.""" + + def __repr__(self): + if self.__origin__ is None: + return super().__repr__() + return self._tree_repr(self._subs_tree()) + + def _tree_repr(self, tree): + if _gorg(self) is not Callable: + return super()._tree_repr(tree) + # For actual Callable (not its subclass) we override + # super()._tree_repr() for nice formatting. + arg_list = [] + for arg in tree[1:]: + if arg == (): + arg_list.append('[]') + elif not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) + else: + arg_list.append(arg[0]._tree_repr(arg)) + if len(arg_list) == 2: + return repr(tree[0]) + '[%s]' % ', '.join(arg_list) + return (repr(tree[0]) + + '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1])) + + def __getitem__(self, parameters): + """ A thin wrapper around __getitem_inner__ to provide the latter + with hashable arguments to improve speed. + """ + + if self.__origin__ is not None or not _geqv(self, Callable): + return super().__getitem__(parameters) + if not isinstance(parameters, tuple) or len(parameters) != 2: + raise TypeError("Callable must be used as " + "Callable[[arg, ...], result].") + args, result = parameters + if args is ...: + parameters = (..., result) + elif args == []: + parameters = ((), result) else: - origin = _gorg(cls) - obj = cls.__next_in_mro__.__new__(origin) - try: - obj.__orig_class__ = cls - except AttributeError: - pass - obj.__init__(*args, **kwds) - return obj + if not isinstance(args, list): + raise TypeError("Callable[args, result]: args must be a list." + " Got %.100r." % (args,)) + parameters = tuple(args) + (result,) + return self.__getitem_inner__(parameters) + + @_tp_cache + def __getitem_inner__(self, parameters): + *args, result = parameters + msg = "Callable[args, result]: result must be a type." + result = _type_check(result, msg) + if args == [...,]: + return super().__getitem__((_TypingEllipsis, result)) + if args == [(),]: + return super().__getitem__((_TypingEmpty, result)) + msg = "Callable[[arg, ...], result]: each arg must be a type." + args = tuple(_type_check(arg, msg) for arg in args) + parameters = args + (result,) + return super().__getitem__(parameters) + + +class Callable(extra=collections_abc.Callable, metaclass = CallableMeta): + """Callable type; Callable[[int], str] is a function of (int) -> str. + + The subscription syntax must always be used with exactly two + values: the argument list and the return type. The argument list + must be a list of types; the return type must be a single type. + + There is no syntax to indicate optional or keyword arguments, + such function types are rarely used as callback types. + """ + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Callable): + raise TypeError("Type Callable cannot be instantiated; " + "use a non-abstract subclass instead") + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) class _ClassVar(_FinalTypingBase, _root=True): @@ -1208,17 +1283,10 @@ return self return type(self)(new_tp, _root=True) - def _get_type_vars(self, tvars): - if self.__type__: - _get_type_vars([self.__type__], tvars) - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(_replace_arg(self.__type__, tvars, args)) + r += '[{}]'.format(_type_repr(self.__type__)) return r def __hash__(self): @@ -1231,6 +1299,7 @@ return self.__type__ == other.__type__ return self is other + ClassVar = _ClassVar(_root=True) @@ -1533,6 +1602,7 @@ attr != '__origin__' and attr != '__orig_bases__' and attr != '__extra__' and + attr != '__tree_hash__' and attr != '__module__'): attrs.add(attr) @@ -1723,7 +1793,7 @@ if _geqv(cls, List): raise TypeError("Type List cannot be instantiated; " "use list() instead") - return list.__new__(cls, *args, **kwds) + return _generic_new(list, cls, *args, **kwds) class Set(set, MutableSet[T], extra=set): @@ -1734,7 +1804,7 @@ if _geqv(cls, Set): raise TypeError("Type Set cannot be instantiated; " "use set() instead") - return set.__new__(cls, *args, **kwds) + return _generic_new(set, cls, *args, **kwds) class FrozenSet(frozenset, AbstractSet[T_co], extra=frozenset): @@ -1744,7 +1814,7 @@ if _geqv(cls, FrozenSet): raise TypeError("Type FrozenSet cannot be instantiated; " "use frozenset() instead") - return frozenset.__new__(cls, *args, **kwds) + return _generic_new(frozenset, cls, *args, **kwds) class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView): @@ -1781,7 +1851,7 @@ if _geqv(cls, Dict): raise TypeError("Type Dict cannot be instantiated; " "use dict() instead") - return dict.__new__(cls, *args, **kwds) + return _generic_new(dict, cls, *args, **kwds) class DefaultDict(collections.defaultdict, MutableMapping[KT, VT], extra=collections.defaultdict): @@ -1792,7 +1862,7 @@ if _geqv(cls, DefaultDict): raise TypeError("Type DefaultDict cannot be instantiated; " "use collections.defaultdict() instead") - return collections.defaultdict.__new__(cls, *args, **kwds) + return _generic_new(collections.defaultdict, cls, *args, **kwds) # Determine what base class to use for Generator. if hasattr(collections_abc, 'Generator'): @@ -1811,7 +1881,7 @@ if _geqv(cls, Generator): raise TypeError("Type Generator cannot be instantiated; " "create a subclass instead") - return super().__new__(cls, *args, **kwds) + return _generic_new(_G_base, cls, *args, **kwds) # Internal type variable used for Type[]. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 11:55:13 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 15:55:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328556=3A_updates_to_typing=2Epy_=283=2E5-=3E3=2E6=29?= Message-ID: <20161029155513.22391.49013.CE9F753A@psf.io> https://hg.python.org/cpython/rev/d2b5c3bfa2b5 changeset: 104796:d2b5c3bfa2b5 branch: 3.6 parent: 104793:0c910ea1c968 parent: 104795:a47b07d0aba0 user: Guido van Rossum date: Sat Oct 29 08:54:57 2016 -0700 summary: Issue #28556: updates to typing.py (3.5->3.6) files: Lib/test/test_typing.py | 157 +++++- Lib/typing.py | 754 +++++++++++++++------------ 2 files changed, 548 insertions(+), 363 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -142,8 +142,9 @@ self.assertEqual(Union[X, X], X) self.assertNotEqual(Union[X, int], Union[X]) self.assertNotEqual(Union[X, int], Union[int]) - self.assertEqual(Union[X, int].__union_params__, (X, int)) - self.assertEqual(Union[X, int].__union_set_params__, {X, int}) + self.assertEqual(Union[X, int].__args__, (X, int)) + self.assertEqual(Union[X, int].__parameters__, (X,)) + self.assertIs(Union[X, int].__origin__, Union) def test_union_constrained(self): A = TypeVar('A', str, bytes) @@ -312,8 +313,6 @@ def test_basics(self): with self.assertRaises(TypeError): - issubclass(Tuple[int, str], Tuple) - with self.assertRaises(TypeError): issubclass(Tuple, Tuple[int, str]) with self.assertRaises(TypeError): issubclass(tuple, Tuple[int, str]) @@ -367,22 +366,6 @@ self.assertNotEqual(Callable[[int], int], Callable[[], int]) self.assertNotEqual(Callable[[int], int], Callable) - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - - class C(Callable): - pass - - with self.assertRaises(TypeError): - - class C(type(Callable)): - pass - - with self.assertRaises(TypeError): - - class C(Callable[[int], int]): - pass - def test_cannot_instantiate(self): with self.assertRaises(TypeError): Callable() @@ -710,6 +693,138 @@ self.assertEqual(C.__orig_bases__, (List[T][U][V],)) self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) + def test_extended_generic_rules_eq(self): + T = TypeVar('T') + U = TypeVar('U') + self.assertEqual(Tuple[T, T][int], Tuple[int, int]) + self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) + with self.assertRaises(TypeError): + Tuple[T, int][()] + with self.assertRaises(TypeError): + Tuple[T, U][T, ...] + + self.assertEqual(Union[T, int][int], int) + self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) + class Base: ... + class Derived(Base): ... + self.assertEqual(Union[T, Base][Derived], Base) + with self.assertRaises(TypeError): + Union[T, int][1] + + self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) + self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) + with self.assertRaises(TypeError): + Callable[[T], U][..., int] + with self.assertRaises(TypeError): + Callable[[T], U][[], int] + + def test_extended_generic_rules_repr(self): + T = TypeVar('T') + self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''), + 'Union[Tuple, Callable]') + self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), + 'Tuple') + self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), + 'Callable[..., Union[int, NoneType]]') + self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), + 'Callable[[], List[int]]') + + def test_generic_forvard_ref(self): + def foobar(x: List[List['T']]): ... + T = TypeVar('T') + self.assertEqual(get_type_hints(foobar, globals(), locals()), {'x': List[List[T]]}) + def barfoo(x: Tuple[T, ...]): ... + self.assertIs(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) + + def test_extended_generic_rules_subclassing(self): + class T1(Tuple[T, KT]): ... + class T2(Tuple[T, ...]): ... + class C1(Callable[[T], T]): ... + class C2(Callable[..., int]): + def __call__(self): + return None + + self.assertEqual(T1.__parameters__, (T, KT)) + self.assertEqual(T1[int, str].__args__, (int, str)) + self.assertEqual(T1[int, T].__origin__, T1) + + self.assertEqual(T2.__parameters__, (T,)) + with self.assertRaises(TypeError): + T1[int] + with self.assertRaises(TypeError): + T2[int, str] + + self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') + self.assertEqual(C2.__parameters__, ()) + self.assertIsInstance(C2(), collections_abc.Callable) + self.assertIsSubclass(C2, collections_abc.Callable) + self.assertIsSubclass(C1, collections_abc.Callable) + self.assertIsInstance(T1(), tuple) + self.assertIsSubclass(T2, tuple) + self.assertIsSubclass(Tuple[int, ...], typing.Sequence) + self.assertIsSubclass(Tuple[int, ...], typing.Iterable) + + def test_fail_with_bare_union(self): + with self.assertRaises(TypeError): + List[Union] + with self.assertRaises(TypeError): + Tuple[Optional] + with self.assertRaises(TypeError): + ClassVar[ClassVar] + with self.assertRaises(TypeError): + List[ClassVar[int]] + + def test_fail_with_bare_generic(self): + T = TypeVar('T') + with self.assertRaises(TypeError): + List[Generic] + with self.assertRaises(TypeError): + Tuple[Generic[T]] + with self.assertRaises(TypeError): + List[typing._Protocol] + + def test_type_erasure_special(self): + T = TypeVar('T') + class MyTup(Tuple[T, T]): ... + self.assertIs(MyTup[int]().__class__, MyTup) + self.assertIs(MyTup[int]().__orig_class__, MyTup[int]) + class MyCall(Callable[..., T]): + def __call__(self): return None + self.assertIs(MyCall[T]().__class__, MyCall) + self.assertIs(MyCall[T]().__orig_class__, MyCall[T]) + class MyDict(typing.Dict[T, T]): ... + self.assertIs(MyDict[int]().__class__, MyDict) + self.assertIs(MyDict[int]().__orig_class__, MyDict[int]) + class MyDef(typing.DefaultDict[str, T]): ... + self.assertIs(MyDef[int]().__class__, MyDef) + self.assertIs(MyDef[int]().__orig_class__, MyDef[int]) + + def test_all_repr_eq_any(self): + objs = (getattr(typing, el) for el in typing.__all__) + for obj in objs: + self.assertNotEqual(repr(obj), '') + self.assertEqual(obj, obj) + if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: + self.assertEqual(obj[Any].__args__, (Any,)) + if isinstance(obj, type): + for base in obj.__mro__: + self.assertNotEqual(repr(base), '') + self.assertEqual(base, base) + + def test_substitution_helper(self): + T = TypeVar('T') + KT = TypeVar('KT') + VT = TypeVar('VT') + class Map(Generic[KT, VT]): + def meth(self, k: KT, v: VT): ... + StrMap = Map[str, T] + obj = StrMap[int]() + + new_args = typing._subs_tree(obj.__orig_class__) + new_annots = {k: typing._replace_arg(v, type(obj).__parameters__, new_args) + for k, v in obj.meth.__annotations__.items()} + + self.assertEqual(new_annots, {'k': str, 'v': int}) def test_pickle(self): global C # pickle wants to reference the class by name @@ -752,7 +867,7 @@ X = C[int] self.assertEqual(X.__module__, __name__) if not PY32: - self.assertEqual(X.__qualname__, 'C') + self.assertTrue(X.__qualname__.endswith('..C')) self.assertEqual(repr(X).split('.')[-1], 'C[int]') class Y(C[int]): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -333,8 +333,7 @@ def _eval_type(t, globalns, localns): if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): return t._eval_type(globalns, localns) - else: - return t + return t def _type_check(arg, msg): @@ -353,8 +352,14 @@ return type(None) if isinstance(arg, str): arg = _ForwardRef(arg) - if not isinstance(arg, (type, _TypingBase)) and not callable(arg): + if (isinstance(arg, _TypingBase) and type(arg).__name__ == '_ClassVar' or + not isinstance(arg, (type, _TypingBase)) and not callable(arg)): raise TypeError(msg + " Got %.100r." % (arg,)) + # Bare Union etc. are not valid as type arguments + if (type(arg).__name__ in ('_Union', '_Optional') + and not getattr(arg, '__origin__', None) + or isinstance(arg, TypingMeta) and _gorg(arg) in (Generic, _Protocol)): + raise TypeError("Plain %s is not valid as type argument" % arg) return arg @@ -369,10 +374,12 @@ if isinstance(obj, type) and not isinstance(obj, TypingMeta): if obj.__module__ == 'builtins': return _qualname(obj) - else: - return '%s.%s' % (obj.__module__, _qualname(obj)) - else: - return repr(obj) + return '%s.%s' % (obj.__module__, _qualname(obj)) + if obj is ...: + return('...') + if isinstance(obj, types.FunctionType): + return obj.__name__ + return repr(obj) class _Any(_FinalTypingBase, _root=True): @@ -502,7 +509,107 @@ AnyStr = TypeVar('AnyStr', bytes, str) +def _replace_arg(arg, tvars, args): + """ A helper fuunction: replace arg if it is a type variable + found in tvars with corresponding substitution from args or + with corresponding substitution sub-tree if arg is a generic type. + """ + + if tvars is None: + tvars = [] + if hasattr(arg, '_subs_tree'): + return arg._subs_tree(tvars, args) + if isinstance(arg, TypeVar): + for i, tvar in enumerate(tvars): + if arg == tvar: + return args[i] + return arg + + +def _subs_tree(cls, tvars=None, args=None): + """ Calculate substitution tree for generic cls after + replacing its type parameters with substitutions in tvars -> args (if any). + Repeat the same cyclicaly following __origin__'s. + """ + + if cls.__origin__ is None: + return cls + # Make of chain of origins (i.e. cls -> cls.__origin__) + current = cls.__origin__ + orig_chain = [] + while current.__origin__ is not None: + orig_chain.append(current) + current = current.__origin__ + # Replace type variables in __args__ if asked ... + tree_args = [] + for arg in cls.__args__: + tree_args.append(_replace_arg(arg, tvars, args)) + # ... then continue replacing down the origin chain. + for ocls in orig_chain: + new_tree_args = [] + for i, arg in enumerate(ocls.__args__): + new_tree_args.append(_replace_arg(arg, ocls.__parameters__, tree_args)) + tree_args = new_tree_args + return tree_args + + +def _remove_dups_flatten(parameters): + """ A helper for Union creation and substitution: flatten Union's + among parameters, then remove duplicates and strict subclasses. + """ + + # Flatten out Union[Union[...], ...]. + params = [] + for p in parameters: + if isinstance(p, _Union) and p.__origin__ is Union: + params.extend(p.__args__) + elif isinstance(p, tuple) and len(p) > 0 and p[0] is Union: + params.extend(p[1:]) + else: + params.append(p) + # Weed out strict duplicates, preserving the first of each occurrence. + all_params = set(params) + if len(all_params) < len(params): + new_params = [] + for t in params: + if t in all_params: + new_params.append(t) + all_params.remove(t) + params = new_params + assert not all_params, all_params + # Weed out subclasses. + # E.g. Union[int, Employee, Manager] == Union[int, Employee]. + # If object is present it will be sole survivor among proper classes. + # Never discard type variables. + # (In particular, Union[str, AnyStr] != AnyStr.) + all_params = set(params) + for t1 in params: + if not isinstance(t1, type): + continue + if any(isinstance(t2, type) and issubclass(t1, t2) + for t2 in all_params - {t1} + if not (isinstance(t2, GenericMeta) and + t2.__origin__ is not None)): + all_params.remove(t1) + return tuple(t for t in params if t in all_params) + + +def _check_generic(cls, parameters): + # Check correct count for parameters of a generic cls. + if not cls.__parameters__: + raise TypeError("%s is not a generic class" % repr(cls)) + alen = len(parameters) + elen = len(cls.__parameters__) + if alen != elen: + raise TypeError("Too %s parameters for %s; actual %s, expected %s" % + ("many" if alen > elen else "few", repr(cls), alen, elen)) + + def _tp_cache(func): + """ Caching for __getitem__ of generic types with a fallback to + original function for non-hashable arguments. + """ + cached = functools.lru_cache()(func) @functools.wraps(func) def inner(*args, **kwds): @@ -555,100 +662,100 @@ - You cannot subclass or instantiate a union. - - You cannot write Union[X][Y] (what would it mean?). - - You can use Optional[X] as a shorthand for Union[X, None]. """ - __slots__ = ('__union_params__', '__union_set_params__') - - def __new__(cls, parameters=None, *args, _root=False): - self = super().__new__(cls, parameters, *args, _root=_root) - if parameters is None: - self.__union_params__ = None - self.__union_set_params__ = None + __slots__ = ('__parameters__', '__args__', '__origin__', '__tree_hash__') + + def __new__(cls, parameters=None, origin=None, *args, _root=False): + self = super().__new__(cls, parameters, origin, *args, _root=_root) + if origin is None: + self.__parameters__ = None + self.__args__ = None + self.__origin__ = None + self.__tree_hash__ = hash(frozenset(('Union',))) return self if not isinstance(parameters, tuple): raise TypeError("Expected parameters=") - # Flatten out Union[Union[...], ...] and type-check non-Union args. - params = [] - msg = "Union[arg, ...]: each arg must be a type." - for p in parameters: - if isinstance(p, _Union): - params.extend(p.__union_params__) + if origin is Union: + parameters = _remove_dups_flatten(parameters) + # It's not a union if there's only one type left. + if len(parameters) == 1: + return parameters[0] + self.__parameters__ = _type_vars(parameters) + self.__args__ = parameters + self.__origin__ = origin + # Pre-calculate the __hash__ on instantiation. + # This improves speed for complex substitutions. + subs_tree = self._subs_tree() + if isinstance(subs_tree, tuple): + self.__tree_hash__ = hash(frozenset(subs_tree)) + else: + self.__tree_hash__ = hash(subs_tree) + return self + + def _eval_type(self, globalns, localns): + if self.__args__ is None: + return self + ev_args = tuple(_eval_type(t, globalns, localns) for t in self.__args__) + ev_origin = _eval_type(self.__origin__, globalns, localns) + if ev_args == self.__args__ and ev_origin == self.__origin__: + # Everything is already evaluated. + return self + return self.__class__(ev_args, ev_origin, _root=True) + + def _get_type_vars(self, tvars): + if self.__origin__ and self.__parameters__: + _get_type_vars(self.__parameters__, tvars) + + def __repr__(self): + if self.__origin__ is None: + return super().__repr__() + tree = self._subs_tree() + if not isinstance(tree, tuple): + return repr(tree) + return tree[0]._tree_repr(tree) + + def _tree_repr(self, tree): + arg_list = [] + for arg in tree[1:]: + if not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) else: - params.append(_type_check(p, msg)) - # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - # Weed out subclasses. - # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If object is present it will be sole survivor among proper classes. - # Never discard type variables. - # (In particular, Union[str, AnyStr] != AnyStr.) - all_params = set(params) - for t1 in params: - if not isinstance(t1, type): - continue - if any(isinstance(t2, type) and issubclass(t1, t2) - for t2 in all_params - {t1} - if not (isinstance(t2, GenericMeta) and - t2.__origin__ is not None)): - all_params.remove(t1) - # It's not a union if there's only one type left. - if len(all_params) == 1: - return all_params.pop() - self.__union_params__ = tuple(t for t in params if t in all_params) - self.__union_set_params__ = frozenset(self.__union_params__) - return self - - def _eval_type(self, globalns, localns): - p = tuple(_eval_type(t, globalns, localns) - for t in self.__union_params__) - if p == self.__union_params__: - return self - else: - return self.__class__(p, _root=True) - - def _get_type_vars(self, tvars): - if self.__union_params__: - _get_type_vars(self.__union_params__, tvars) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__union_params__: - r += '[%s]' % (', '.join(_replace_arg(t, tvars, args) - for t in self.__union_params__)) - return r + arg_list.append(arg[0]._tree_repr(arg)) + return super().__repr__() + '[%s]' % ', '.join(arg_list) @_tp_cache def __getitem__(self, parameters): - if self.__union_params__ is not None: - raise TypeError( - "Cannot subscript an existing Union. Use Union[u, t] instead.") if parameters == (): raise TypeError("Cannot take a Union of no types.") if not isinstance(parameters, tuple): parameters = (parameters,) - return self.__class__(parameters, _root=True) + if self.__origin__ is None: + msg = "Union[arg, ...]: each arg must be a type." + else: + msg = "Parameters to generic types must be types." + parameters = tuple(_type_check(p, msg) for p in parameters) + if self is not Union: + _check_generic(self, parameters) + return self.__class__(parameters, origin=self, _root=True) + + def _subs_tree(self, tvars=None, args=None): + if self is Union: + return Union # Nothing to substitute + tree_args = _subs_tree(self, tvars, args) + tree_args = _remove_dups_flatten(tree_args) + if len(tree_args) == 1: + return tree_args[0] # Union of a single type is that type + return (Union,) + tree_args def __eq__(self, other): if not isinstance(other, _Union): - return NotImplemented - return self.__union_set_params__ == other.__union_set_params__ + return self._subs_tree() == other + return self.__tree_hash__ == other.__tree_hash__ def __hash__(self): - return hash(self.__union_set_params__) + return self.__tree_hash__ def __instancecheck__(self, obj): raise TypeError("Unions cannot be used with isinstance().") @@ -677,195 +784,6 @@ Optional = _Optional(_root=True) -class _Tuple(_FinalTypingBase, _root=True): - """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. - - Example: Tuple[T1, T2] is a tuple of two elements corresponding - to type variables T1 and T2. Tuple[int, float, str] is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. - """ - - __slots__ = ('__tuple_params__', '__tuple_use_ellipsis__') - - def __init__(self, parameters=None, - use_ellipsis=False, _root=False): - self.__tuple_params__ = parameters - self.__tuple_use_ellipsis__ = use_ellipsis - - def _get_type_vars(self, tvars): - if self.__tuple_params__: - _get_type_vars(self.__tuple_params__, tvars) - - def _eval_type(self, globalns, localns): - tp = self.__tuple_params__ - if tp is None: - return self - p = tuple(_eval_type(t, globalns, localns) for t in tp) - if p == self.__tuple_params__: - return self - else: - return self.__class__(p, _root=True) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__tuple_params__ is not None: - params = [_replace_arg(p, tvars, args) for p in self.__tuple_params__] - if self.__tuple_use_ellipsis__: - params.append('...') - if not params: - params.append('()') - r += '[%s]' % ( - ', '.join(params)) - return r - - @_tp_cache - def __getitem__(self, parameters): - if self.__tuple_params__ is not None: - raise TypeError("Cannot re-parameterize %r" % (self,)) - if not isinstance(parameters, tuple): - parameters = (parameters,) - if len(parameters) == 2 and parameters[1] == Ellipsis: - parameters = parameters[:1] - use_ellipsis = True - msg = "Tuple[t, ...]: t must be a type." - else: - use_ellipsis = False - msg = "Tuple[t0, t1, ...]: each t must be a type." - parameters = tuple(_type_check(p, msg) for p in parameters) - return self.__class__(parameters, - use_ellipsis=use_ellipsis, _root=True) - - def __eq__(self, other): - if not isinstance(other, _Tuple): - return NotImplemented - return (self.__tuple_params__ == other.__tuple_params__ and - self.__tuple_use_ellipsis__ == other.__tuple_use_ellipsis__) - - def __hash__(self): - return hash((self.__tuple_params__, self.__tuple_use_ellipsis__)) - - def __instancecheck__(self, obj): - if self.__tuple_params__ == None: - return isinstance(obj, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__tuple_params__ == None: - return issubclass(cls, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with issubclass().") - - -Tuple = _Tuple(_root=True) - - -class _Callable(_FinalTypingBase, _root=True): - """Callable type; Callable[[int], str] is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - """ - - __slots__ = ('__args__', '__result__') - - def __init__(self, args=None, result=None, _root=False): - if args is None and result is None: - pass - else: - if args is not Ellipsis: - if not isinstance(args, list): - raise TypeError("Callable[args, result]: " - "args must be a list." - " Got %.100r." % (args,)) - msg = "Callable[[arg, ...], result]: each arg must be a type." - args = tuple(_type_check(arg, msg) for arg in args) - msg = "Callable[args, result]: result must be a type." - result = _type_check(result, msg) - self.__args__ = args - self.__result__ = result - - def _get_type_vars(self, tvars): - if self.__args__ and self.__args__ is not Ellipsis: - _get_type_vars(self.__args__, tvars) - if self.__result__: - _get_type_vars([self.__result__], tvars) - - def _eval_type(self, globalns, localns): - if self.__args__ is None and self.__result__ is None: - return self - if self.__args__ is Ellipsis: - args = self.__args__ - else: - args = [_eval_type(t, globalns, localns) for t in self.__args__] - result = _eval_type(self.__result__, globalns, localns) - if args == self.__args__ and result == self.__result__: - return self - else: - return self.__class__(args, result, _root=True) - - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - r = super().__repr__() - if self.__args__ is not None or self.__result__ is not None: - if self.__args__ is Ellipsis: - args_r = '...' - else: - args_r = '[%s]' % ', '.join(_replace_arg(t, tvars, args) - for t in self.__args__) - r += '[%s, %s]' % (args_r, _replace_arg(self.__result__, tvars, args)) - return r - - def __getitem__(self, parameters): - if self.__args__ is not None or self.__result__ is not None: - raise TypeError("This Callable type is already parameterized.") - if not isinstance(parameters, tuple) or len(parameters) != 2: - raise TypeError( - "Callable must be used as Callable[[arg, ...], result].") - args, result = parameters - return self.__class__(args, result, _root=True) - - def __eq__(self, other): - if not isinstance(other, _Callable): - return NotImplemented - return (self.__args__ == other.__args__ and - self.__result__ == other.__result__) - - def __hash__(self): - return hash(self.__args__) ^ hash(self.__result__) - - def __instancecheck__(self, obj): - # For unparametrized Callable we allow this, because - # typing.Callable should be equivalent to - # collections.abc.Callable. - if self.__args__ is None and self.__result__ is None: - return isinstance(obj, collections_abc.Callable) - else: - raise TypeError("Parameterized Callable cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__args__ is None and self.__result__ is None: - return issubclass(cls, collections_abc.Callable) - else: - raise TypeError("Parameterized Callable cannot be used " - "with issubclass().") - - -Callable = _Callable(_root=True) - - def _gorg(a): """Return the farthest origin of a generic class.""" assert isinstance(a, GenericMeta) @@ -889,16 +807,6 @@ return _gorg(a) is _gorg(b) -def _replace_arg(arg, tvars, args): - if hasattr(arg, '_subs_repr'): - return arg._subs_repr(tvars, args) - if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg == tvar: - return args[i] - return _type_repr(arg) - - def _next_in_mro(cls): """Helper for Generic.__new__. @@ -1011,7 +919,11 @@ self = super().__new__(cls, name, bases, namespace, _root=True) self.__parameters__ = tvars - self.__args__ = args + # Be prepared that GenericMeta will be subclassed by TupleMeta + # and CallableMeta, those two allow ..., (), or [] in __args___. + self.__args__ = tuple(... if a is _TypingEllipsis else + () if a is _TypingEmpty else + a for a in args) if args else None self.__origin__ = origin self.__extra__ = extra # Speed hack (https://github.com/python/typing/issues/196). @@ -1029,55 +941,69 @@ self.__subclasshook__ = _make_subclasshook(self) if isinstance(extra, abc.ABCMeta): self._abc_registry = extra._abc_registry + + if origin and hasattr(origin, '__qualname__'): # Fix for Python 3.2. + self.__qualname__ = origin.__qualname__ + self.__tree_hash__ = hash(self._subs_tree()) if origin else hash((self.__name__,)) return self def _get_type_vars(self, tvars): if self.__origin__ and self.__parameters__: _get_type_vars(self.__parameters__, tvars) + def _eval_type(self, globalns, localns): + ev_origin = (self.__origin__._eval_type(globalns, localns) + if self.__origin__ else None) + ev_args = tuple(_eval_type(a, globalns, localns) for a + in self.__args__) if self.__args__ else None + if ev_origin == self.__origin__ and ev_args == self.__args__: + return self + return self.__class__(self.__name__, + self.__bases__, + dict(self.__dict__), + tvars=_type_vars(ev_args) if ev_args else None, + args=ev_args, + origin=ev_origin, + extra=self.__extra__, + orig_bases=self.__orig_bases__) + def __repr__(self): if self.__origin__ is None: return super().__repr__() - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): - assert len(tvars) == len(args) - # Construct the chain of __origin__'s. - current = self.__origin__ - orig_chain = [] - while current.__origin__ is not None: - orig_chain.append(current) - current = current.__origin__ - # Replace type variables in __args__ if asked ... - str_args = [] - for arg in self.__args__: - str_args.append(_replace_arg(arg, tvars, args)) - # ... then continue replacing down the origin chain. - for cls in orig_chain: - new_str_args = [] - for i, arg in enumerate(cls.__args__): - new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args)) - str_args = new_str_args - return super().__repr__() + '[%s]' % ', '.join(str_args) + return self._tree_repr(self._subs_tree()) + + def _tree_repr(self, tree): + arg_list = [] + for arg in tree[1:]: + if arg == (): + arg_list.append('()') + elif not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) + else: + arg_list.append(arg[0]._tree_repr(arg)) + return super().__repr__() + '[%s]' % ', '.join(arg_list) + + def _subs_tree(self, tvars=None, args=None): + if self.__origin__ is None: + return self + tree_args = _subs_tree(self, tvars, args) + return (_gorg(self),) + tuple(tree_args) def __eq__(self, other): if not isinstance(other, GenericMeta): return NotImplemented - if self.__origin__ is not None: - return (self.__origin__ is other.__origin__ and - self.__args__ == other.__args__ and - self.__parameters__ == other.__parameters__) - else: + if self.__origin__ is None or other.__origin__ is None: return self is other + return self.__tree_hash__ == other.__tree_hash__ def __hash__(self): - return hash((self.__name__, self.__parameters__)) + return self.__tree_hash__ @_tp_cache def __getitem__(self, params): if not isinstance(params, tuple): params = (params,) - if not params: + if not params and not _gorg(self) is Tuple: raise TypeError( "Parameter list to %s[...] cannot be empty" % _qualname(self)) msg = "Parameters to generic types must be types." @@ -1092,6 +1018,9 @@ "Parameters to Generic[...] must all be unique") tvars = params args = params + elif self in (Tuple, Callable): + tvars = _type_vars(params) + args = params elif self is _Protocol: # _Protocol is internal, don't check anything. tvars = params @@ -1102,14 +1031,7 @@ repr(self)) else: # Subscripting a regular Generic subclass. - if not self.__parameters__: - raise TypeError("%s is not a generic class" % repr(self)) - alen = len(params) - elen = len(self.__parameters__) - if alen != elen: - raise TypeError( - "Too %s parameters for %s; actual %s, expected %s" % - ("many" if alen > elen else "few", repr(self), alen, elen)) + _check_generic(self, params) tvars = _type_vars(params) args = params return self.__class__(self.__name__, @@ -1134,6 +1056,22 @@ Generic = None +def _generic_new(base_cls, cls, *args, **kwds): + # Assure type is erased on instantiation, + # but attempt to store it in __orig_class__ + if cls.__origin__ is None: + return base_cls.__new__(cls) + else: + origin = _gorg(cls) + obj = base_cls.__new__(origin) + try: + obj.__orig_class__ = cls + except AttributeError: + pass + obj.__init__(*args, **kwds) + return obj + + class Generic(metaclass=GenericMeta): """Abstract base class for generic types. @@ -1158,17 +1096,154 @@ __slots__ = () def __new__(cls, *args, **kwds): - if cls.__origin__ is None: - return cls.__next_in_mro__.__new__(cls) + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) + + +class _TypingEmpty: + """Placeholder for () or []. Used by TupleMeta and CallableMeta + to allow empy list/tuple in specific places, without allowing them + to sneak in where prohibited. + """ + + +class _TypingEllipsis: + """Ditto for ...""" + + +class TupleMeta(GenericMeta): + """Metaclass for Tuple""" + + @_tp_cache + def __getitem__(self, parameters): + if self.__origin__ is not None or not _geqv(self, Tuple): + # Normal generic rules apply if this is not the first subscription + # or a subscription of a subclass. + return super().__getitem__(parameters) + if parameters == (): + return super().__getitem__((_TypingEmpty,)) + if not isinstance(parameters, tuple): + parameters = (parameters,) + if len(parameters) == 2 and parameters[1] is ...: + msg = "Tuple[t, ...]: t must be a type." + p = _type_check(parameters[0], msg) + return super().__getitem__((p, _TypingEllipsis)) + msg = "Tuple[t0, t1, ...]: each t must be a type." + parameters = tuple(_type_check(p, msg) for p in parameters) + return super().__getitem__(parameters) + + def __instancecheck__(self, obj): + if self.__args__ == None: + return isinstance(obj, tuple) + raise TypeError("Parameterized Tuple cannot be used " + "with isinstance().") + + def __subclasscheck__(self, cls): + if self.__args__ == None: + return issubclass(cls, tuple) + raise TypeError("Parameterized Tuple cannot be used " + "with issubclass().") + + +class Tuple(tuple, extra=tuple, metaclass=TupleMeta): + """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. + + Example: Tuple[T1, T2] is a tuple of two elements corresponding + to type variables T1 and T2. Tuple[int, float, str] is a tuple + of an int, a float and a string. + + To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. + """ + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Tuple): + raise TypeError("Type Tuple cannot be instantiated; " + "use tuple() instead") + return _generic_new(tuple, cls, *args, **kwds) + + +class CallableMeta(GenericMeta): + """ Metaclass for Callable.""" + + def __repr__(self): + if self.__origin__ is None: + return super().__repr__() + return self._tree_repr(self._subs_tree()) + + def _tree_repr(self, tree): + if _gorg(self) is not Callable: + return super()._tree_repr(tree) + # For actual Callable (not its subclass) we override + # super()._tree_repr() for nice formatting. + arg_list = [] + for arg in tree[1:]: + if arg == (): + arg_list.append('[]') + elif not isinstance(arg, tuple): + arg_list.append(_type_repr(arg)) + else: + arg_list.append(arg[0]._tree_repr(arg)) + if len(arg_list) == 2: + return repr(tree[0]) + '[%s]' % ', '.join(arg_list) + return (repr(tree[0]) + + '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1])) + + def __getitem__(self, parameters): + """ A thin wrapper around __getitem_inner__ to provide the latter + with hashable arguments to improve speed. + """ + + if self.__origin__ is not None or not _geqv(self, Callable): + return super().__getitem__(parameters) + if not isinstance(parameters, tuple) or len(parameters) != 2: + raise TypeError("Callable must be used as " + "Callable[[arg, ...], result].") + args, result = parameters + if args is ...: + parameters = (..., result) + elif args == []: + parameters = ((), result) else: - origin = _gorg(cls) - obj = cls.__next_in_mro__.__new__(origin) - try: - obj.__orig_class__ = cls - except AttributeError: - pass - obj.__init__(*args, **kwds) - return obj + if not isinstance(args, list): + raise TypeError("Callable[args, result]: args must be a list." + " Got %.100r." % (args,)) + parameters = tuple(args) + (result,) + return self.__getitem_inner__(parameters) + + @_tp_cache + def __getitem_inner__(self, parameters): + *args, result = parameters + msg = "Callable[args, result]: result must be a type." + result = _type_check(result, msg) + if args == [...,]: + return super().__getitem__((_TypingEllipsis, result)) + if args == [(),]: + return super().__getitem__((_TypingEmpty, result)) + msg = "Callable[[arg, ...], result]: each arg must be a type." + args = tuple(_type_check(arg, msg) for arg in args) + parameters = args + (result,) + return super().__getitem__(parameters) + + +class Callable(extra=collections_abc.Callable, metaclass = CallableMeta): + """Callable type; Callable[[int], str] is a function of (int) -> str. + + The subscription syntax must always be used with exactly two + values: the argument list and the return type. The argument list + must be a list of types; the return type must be a single type. + + There is no syntax to indicate optional or keyword arguments, + such function types are rarely used as callback types. + """ + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Callable): + raise TypeError("Type Callable cannot be instantiated; " + "use a non-abstract subclass instead") + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) class _ClassVar(_FinalTypingBase, _root=True): @@ -1208,17 +1283,10 @@ return self return type(self)(new_tp, _root=True) - def _get_type_vars(self, tvars): - if self.__type__: - _get_type_vars([self.__type__], tvars) - def __repr__(self): - return self._subs_repr([], []) - - def _subs_repr(self, tvars, args): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(_replace_arg(self.__type__, tvars, args)) + r += '[{}]'.format(_type_repr(self.__type__)) return r def __hash__(self): @@ -1231,6 +1299,7 @@ return self.__type__ == other.__type__ return self is other + ClassVar = _ClassVar(_root=True) @@ -1533,6 +1602,7 @@ attr != '__origin__' and attr != '__orig_bases__' and attr != '__extra__' and + attr != '__tree_hash__' and attr != '__module__'): attrs.add(attr) @@ -1723,7 +1793,7 @@ if _geqv(cls, List): raise TypeError("Type List cannot be instantiated; " "use list() instead") - return list.__new__(cls, *args, **kwds) + return _generic_new(list, cls, *args, **kwds) class Set(set, MutableSet[T], extra=set): @@ -1734,7 +1804,7 @@ if _geqv(cls, Set): raise TypeError("Type Set cannot be instantiated; " "use set() instead") - return set.__new__(cls, *args, **kwds) + return _generic_new(set, cls, *args, **kwds) class FrozenSet(frozenset, AbstractSet[T_co], extra=frozenset): @@ -1744,7 +1814,7 @@ if _geqv(cls, FrozenSet): raise TypeError("Type FrozenSet cannot be instantiated; " "use frozenset() instead") - return frozenset.__new__(cls, *args, **kwds) + return _generic_new(frozenset, cls, *args, **kwds) class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView): @@ -1781,7 +1851,7 @@ if _geqv(cls, Dict): raise TypeError("Type Dict cannot be instantiated; " "use dict() instead") - return dict.__new__(cls, *args, **kwds) + return _generic_new(dict, cls, *args, **kwds) class DefaultDict(collections.defaultdict, MutableMapping[KT, VT], extra=collections.defaultdict): @@ -1792,7 +1862,7 @@ if _geqv(cls, DefaultDict): raise TypeError("Type DefaultDict cannot be instantiated; " "use collections.defaultdict() instead") - return collections.defaultdict.__new__(cls, *args, **kwds) + return _generic_new(collections.defaultdict, cls, *args, **kwds) # Determine what base class to use for Generator. if hasattr(collections_abc, 'Generator'): @@ -1811,7 +1881,7 @@ if _geqv(cls, Generator): raise TypeError("Type Generator cannot be instantiated; " "create a subclass instead") - return super().__new__(cls, *args, **kwds) + return _generic_new(_G_base, cls, *args, **kwds) # Internal type variable used for Type[]. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 12:24:06 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 29 Oct 2016 16:24:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Adds_missing_=5Fasyncio=2Epyd_to_installer_and_generally?= =?utf-8?q?_tidies_pyd_management=2E?= Message-ID: <20161029162405.3264.58824.F8207442@psf.io> https://hg.python.org/cpython/rev/c89094dbb853 changeset: 104799:c89094dbb853 parent: 104797:2c75b13ccf82 parent: 104798:5a213604ac08 user: Steve Dower date: Sat Oct 29 09:23:52 2016 -0700 summary: Adds missing _asyncio.pyd to installer and generally tidies pyd management. files: Tools/msi/lib/lib_files.wxs | 2 +- Tools/msi/make_zip.py | 1 + Tools/msi/test/test_files.wxs | 89 +++++----------------- 3 files changed, 23 insertions(+), 69 deletions(-) diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -1,6 +1,6 @@ ? - + diff --git a/Tools/msi/make_zip.py b/Tools/msi/make_zip.py --- a/Tools/msi/make_zip.py +++ b/Tools/msi/make_zip.py @@ -19,6 +19,7 @@ '_ctypes_test', '_testbuffer', '_testcapi', + '_testconsole', '_testimportmultiple', '_testmultiphase', 'xxlimited', diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs --- a/Tools/msi/test/test_files.wxs +++ b/Tools/msi/test/test_files.wxs @@ -1,89 +1,42 @@ ? + - - + + + + - - - - - - - - - - - - - - - + + - - + + + + - - - - - - - - - - - - - - - + + - - + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 12:24:06 2016 From: python-checkins at python.org (steve.dower) Date: Sat, 29 Oct 2016 16:24:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Adds_missing_?= =?utf-8?q?=5Fasyncio=2Epyd_to_installer_and_generally_tidies_pyd_manageme?= =?utf-8?b?bnQu?= Message-ID: <20161029162405.3308.17198.529FDB97@psf.io> https://hg.python.org/cpython/rev/5a213604ac08 changeset: 104798:5a213604ac08 branch: 3.6 parent: 104796:d2b5c3bfa2b5 user: Steve Dower date: Sat Oct 29 09:23:39 2016 -0700 summary: Adds missing _asyncio.pyd to installer and generally tidies pyd management. files: Tools/msi/lib/lib_files.wxs | 2 +- Tools/msi/make_zip.py | 1 + Tools/msi/test/test_files.wxs | 89 +++++----------------- 3 files changed, 23 insertions(+), 69 deletions(-) diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -1,6 +1,6 @@ ? - + diff --git a/Tools/msi/make_zip.py b/Tools/msi/make_zip.py --- a/Tools/msi/make_zip.py +++ b/Tools/msi/make_zip.py @@ -19,6 +19,7 @@ '_ctypes_test', '_testbuffer', '_testcapi', + '_testconsole', '_testimportmultiple', '_testmultiphase', 'xxlimited', diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs --- a/Tools/msi/test/test_files.wxs +++ b/Tools/msi/test/test_files.wxs @@ -1,89 +1,42 @@ ? + - - + + + + - - - - - - - - - - - - - - - + + - - + + + + - - - - - - - - - - - - - - - + + - - + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 15:45:06 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 19:45:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328556=3A_updates_to_typing=2Epy_=28fix_copy=2C_deepco?= =?utf-8?b?cHksIHBpY2tsZSkgKDMuNS0+My42KQ==?= Message-ID: <20161029194506.31027.29422.F4C059C5@psf.io> https://hg.python.org/cpython/rev/465b345559ea changeset: 104801:465b345559ea branch: 3.6 parent: 104798:5a213604ac08 parent: 104800:94010653379c user: Guido van Rossum date: Sat Oct 29 12:44:30 2016 -0700 summary: Issue #28556: updates to typing.py (fix copy, deepcopy, pickle) (3.5->3.6) files: Lib/test/test_typing.py | 19 +++++++++++++++++++ Lib/typing.py | 8 ++++++++ 2 files changed, 27 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4,6 +4,7 @@ import re import sys from unittest import TestCase, main, skipUnless, SkipTest +from copy import copy, deepcopy from typing import Any from typing import TypeVar, AnyStr @@ -845,6 +846,24 @@ self.assertEqual(x.foo, 42) self.assertEqual(x.bar, 'abc') self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) + simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable] + for s in simples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + z = pickle.dumps(s, proto) + x = pickle.loads(z) + self.assertEqual(s, x) + + def test_copy_and_deepcopy(self): + T = TypeVar('T') + class Node(Generic[T]): ... + things = [Union[T, int], Tuple[T, int], Callable[..., T], Callable[[int], int], + Tuple[Any, Any], Node[T], Node[int], Node[Any], typing.Iterable[T], + typing.Iterable[Any], typing.Iterable[int], typing.Dict[int, str], + typing.Dict[T, Any], ClassVar[int], ClassVar[List[T]], Tuple['T', 'T'], + Union['T', int], List['T'], typing.Mapping['T', int]] + for t in things + [Any]: + self.assertEqual(t, copy(t)) + self.assertEqual(t, deepcopy(t)) def test_errors(self): with self.assertRaises(TypeError): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -190,6 +190,9 @@ return self raise TypeError("Cannot instantiate %r" % cls) + def __reduce__(self): + return _trim_name(type(self).__name__) + class _ForwardRef(_TypingBase, _root=True): """Wrapper to hold a forward reference.""" @@ -1051,6 +1054,11 @@ # classes are supposed to be rare anyways. return issubclass(instance.__class__, self) + def __copy__(self): + return self.__class__(self.__name__, self.__bases__, dict(self.__dict__), + self.__parameters__, self.__args__, self.__origin__, + self.__extra__, self.__orig_bases__) + # Prevent checks for Generic to crash when defining Generic. Generic = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 15:45:06 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 19:45:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NTU2?= =?utf-8?q?=3A_updates_to_typing=2Epy_=28fix_copy=2C_deepcopy=2C_pickle=29?= Message-ID: <20161029194506.63082.30575.E70DD4E9@psf.io> https://hg.python.org/cpython/rev/94010653379c changeset: 104800:94010653379c branch: 3.5 parent: 104795:a47b07d0aba0 user: Guido van Rossum date: Sat Oct 29 12:44:29 2016 -0700 summary: Issue #28556: updates to typing.py (fix copy, deepcopy, pickle) files: Lib/test/test_typing.py | 19 +++++++++++++++++++ Lib/typing.py | 8 ++++++++ 2 files changed, 27 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4,6 +4,7 @@ import re import sys from unittest import TestCase, main, skipUnless, SkipTest +from copy import copy, deepcopy from typing import Any from typing import TypeVar, AnyStr @@ -845,6 +846,24 @@ self.assertEqual(x.foo, 42) self.assertEqual(x.bar, 'abc') self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) + simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable] + for s in simples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + z = pickle.dumps(s, proto) + x = pickle.loads(z) + self.assertEqual(s, x) + + def test_copy_and_deepcopy(self): + T = TypeVar('T') + class Node(Generic[T]): ... + things = [Union[T, int], Tuple[T, int], Callable[..., T], Callable[[int], int], + Tuple[Any, Any], Node[T], Node[int], Node[Any], typing.Iterable[T], + typing.Iterable[Any], typing.Iterable[int], typing.Dict[int, str], + typing.Dict[T, Any], ClassVar[int], ClassVar[List[T]], Tuple['T', 'T'], + Union['T', int], List['T'], typing.Mapping['T', int]] + for t in things + [Any]: + self.assertEqual(t, copy(t)) + self.assertEqual(t, deepcopy(t)) def test_errors(self): with self.assertRaises(TypeError): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -190,6 +190,9 @@ return self raise TypeError("Cannot instantiate %r" % cls) + def __reduce__(self): + return _trim_name(type(self).__name__) + class _ForwardRef(_TypingBase, _root=True): """Wrapper to hold a forward reference.""" @@ -1051,6 +1054,11 @@ # classes are supposed to be rare anyways. return issubclass(instance.__class__, self) + def __copy__(self): + return self.__class__(self.__name__, self.__bases__, dict(self.__dict__), + self.__parameters__, self.__args__, self.__origin__, + self.__extra__, self.__orig_bases__) + # Prevent checks for Generic to crash when defining Generic. Generic = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 15:45:07 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 19:45:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328556=3A_updates_to_typing=2Epy_=28fix_copy=2C_?= =?utf-8?b?ZGVlcGNvcHksIHBpY2tsZSkgKDMuNi0+My43KQ==?= Message-ID: <20161029194506.114978.59620.D59A69E0@psf.io> https://hg.python.org/cpython/rev/f23f435494f1 changeset: 104802:f23f435494f1 parent: 104799:c89094dbb853 parent: 104801:465b345559ea user: Guido van Rossum date: Sat Oct 29 12:44:31 2016 -0700 summary: Issue #28556: updates to typing.py (fix copy, deepcopy, pickle) (3.6->3.7) files: Lib/test/test_typing.py | 19 +++++++++++++++++++ Lib/typing.py | 8 ++++++++ 2 files changed, 27 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4,6 +4,7 @@ import re import sys from unittest import TestCase, main, skipUnless, SkipTest +from copy import copy, deepcopy from typing import Any from typing import TypeVar, AnyStr @@ -845,6 +846,24 @@ self.assertEqual(x.foo, 42) self.assertEqual(x.bar, 'abc') self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) + simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable] + for s in simples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + z = pickle.dumps(s, proto) + x = pickle.loads(z) + self.assertEqual(s, x) + + def test_copy_and_deepcopy(self): + T = TypeVar('T') + class Node(Generic[T]): ... + things = [Union[T, int], Tuple[T, int], Callable[..., T], Callable[[int], int], + Tuple[Any, Any], Node[T], Node[int], Node[Any], typing.Iterable[T], + typing.Iterable[Any], typing.Iterable[int], typing.Dict[int, str], + typing.Dict[T, Any], ClassVar[int], ClassVar[List[T]], Tuple['T', 'T'], + Union['T', int], List['T'], typing.Mapping['T', int]] + for t in things + [Any]: + self.assertEqual(t, copy(t)) + self.assertEqual(t, deepcopy(t)) def test_errors(self): with self.assertRaises(TypeError): diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -190,6 +190,9 @@ return self raise TypeError("Cannot instantiate %r" % cls) + def __reduce__(self): + return _trim_name(type(self).__name__) + class _ForwardRef(_TypingBase, _root=True): """Wrapper to hold a forward reference.""" @@ -1051,6 +1054,11 @@ # classes are supposed to be rare anyways. return issubclass(instance.__class__, self) + def __copy__(self): + return self.__class__(self.__name__, self.__bases__, dict(self.__dict__), + self.__parameters__, self.__args__, self.__origin__, + self.__extra__, self.__orig_bases__) + # Prevent checks for Generic to crash when defining Generic. Generic = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 19:06:09 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 23:06:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NTU2?= =?utf-8?q?=3A_updates_to_typing=2Epy_=28add_Coroutine=2C_prohibit_Generic?= =?utf-8?b?W1RdKCkp?= Message-ID: <20161029230609.25402.49254.1F132658@psf.io> https://hg.python.org/cpython/rev/0201a87d773d changeset: 104803:0201a87d773d branch: 3.5 parent: 104800:94010653379c user: Guido van Rossum date: Sat Oct 29 16:05:26 2016 -0700 summary: Issue #28556: updates to typing.py (add Coroutine, prohibit Generic[T]()) files: Lib/test/test_typing.py | 23 ++++++++++++++++++++- Lib/typing.py | 31 +++++++++++++++++++++------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -517,6 +517,9 @@ Y[str, str] def test_generic_errors(self): + T = TypeVar('T') + with self.assertRaises(TypeError): + Generic[T]() with self.assertRaises(TypeError): isinstance([], List[int]) with self.assertRaises(TypeError): @@ -1255,7 +1258,7 @@ ASYNCIO_TESTS = """ import asyncio -T_a = TypeVar('T') +T_a = TypeVar('T_a') class AwaitableWrapper(typing.Awaitable[T_a]): @@ -1404,6 +1407,24 @@ g.send(None) # Run foo() till completion, to avoid warning. @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') + def test_coroutine(self): + ns = {} + exec( + "async def foo():\n" + " return\n", + globals(), ns) + foo = ns['foo'] + g = foo() + self.assertIsInstance(g, typing.Coroutine) + with self.assertRaises(TypeError): + isinstance(g, typing.Coroutine[int]) + self.assertNotIsInstance(foo, typing.Coroutine) + try: + g.send(None) + except StopIteration: + pass + + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterable(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -29,9 +29,6 @@ # ABCs (from collections.abc). 'AbstractSet', # collections.abc.Set. - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', 'ByteString', 'Container', 'Hashable', @@ -47,6 +44,14 @@ 'Sequence', 'Sized', 'ValuesView', + # The following are added depending on presence + # of their non-generic counterparts in stdlib: + # Awaitable, + # AsyncIterator, + # AsyncIterable, + # Coroutine, + # Collection, + # ContextManager # Structural checks, a.k.a. protocols. 'Reversible', @@ -1104,6 +1109,9 @@ __slots__ = () def __new__(cls, *args, **kwds): + if _geqv(cls, Generic): + raise TypeError("Type Generic cannot be instantiated; " + "it can be used only as a base class") return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) @@ -1639,8 +1647,16 @@ if hasattr(collections_abc, 'Awaitable'): class Awaitable(Generic[T_co], extra=collections_abc.Awaitable): __slots__ = () -else: - Awaitable = None + + __all__.append('Awaitable') + + +if hasattr(collections_abc, 'Coroutine'): + class Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co], + extra=collections_abc.Coroutine): + __slots__ = () + + __all__.append('Coroutine') if hasattr(collections_abc, 'AsyncIterable'): @@ -1652,9 +1668,8 @@ extra=collections_abc.AsyncIterator): __slots__ = () -else: - AsyncIterable = None - AsyncIterator = None + __all__.append('AsyncIterable') + __all__.append('AsyncIterator') class Iterable(Generic[T_co], extra=collections_abc.Iterable): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 19:06:10 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 23:06:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328556=3A_updates_to_typing=2Epy_=28add_Coroutin?= =?utf-8?b?ZSwgcHJvaGliaXQgR2VuZXJpY1tUXSgpKQ==?= Message-ID: <20161029230610.7211.4282.DF54C04E@psf.io> https://hg.python.org/cpython/rev/fe842efbe1ed changeset: 104805:fe842efbe1ed parent: 104802:f23f435494f1 parent: 104804:2c2fec17247d user: Guido van Rossum date: Sat Oct 29 16:05:28 2016 -0700 summary: Issue #28556: updates to typing.py (add Coroutine, prohibit Generic[T]()) (3.6->3.7) files: Lib/test/test_typing.py | 23 ++++++++++++++++++++- Lib/typing.py | 31 +++++++++++++++++++++------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -517,6 +517,9 @@ Y[str, str] def test_generic_errors(self): + T = TypeVar('T') + with self.assertRaises(TypeError): + Generic[T]() with self.assertRaises(TypeError): isinstance([], List[int]) with self.assertRaises(TypeError): @@ -1255,7 +1258,7 @@ ASYNCIO_TESTS = """ import asyncio -T_a = TypeVar('T') +T_a = TypeVar('T_a') class AwaitableWrapper(typing.Awaitable[T_a]): @@ -1404,6 +1407,24 @@ g.send(None) # Run foo() till completion, to avoid warning. @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') + def test_coroutine(self): + ns = {} + exec( + "async def foo():\n" + " return\n", + globals(), ns) + foo = ns['foo'] + g = foo() + self.assertIsInstance(g, typing.Coroutine) + with self.assertRaises(TypeError): + isinstance(g, typing.Coroutine[int]) + self.assertNotIsInstance(foo, typing.Coroutine) + try: + g.send(None) + except StopIteration: + pass + + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterable(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -29,9 +29,6 @@ # ABCs (from collections.abc). 'AbstractSet', # collections.abc.Set. - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', 'ByteString', 'Container', 'Hashable', @@ -47,6 +44,14 @@ 'Sequence', 'Sized', 'ValuesView', + # The following are added depending on presence + # of their non-generic counterparts in stdlib: + # Awaitable, + # AsyncIterator, + # AsyncIterable, + # Coroutine, + # Collection, + # ContextManager # Structural checks, a.k.a. protocols. 'Reversible', @@ -1104,6 +1109,9 @@ __slots__ = () def __new__(cls, *args, **kwds): + if _geqv(cls, Generic): + raise TypeError("Type Generic cannot be instantiated; " + "it can be used only as a base class") return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) @@ -1639,8 +1647,16 @@ if hasattr(collections_abc, 'Awaitable'): class Awaitable(Generic[T_co], extra=collections_abc.Awaitable): __slots__ = () -else: - Awaitable = None + + __all__.append('Awaitable') + + +if hasattr(collections_abc, 'Coroutine'): + class Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co], + extra=collections_abc.Coroutine): + __slots__ = () + + __all__.append('Coroutine') if hasattr(collections_abc, 'AsyncIterable'): @@ -1652,9 +1668,8 @@ extra=collections_abc.AsyncIterator): __slots__ = () -else: - AsyncIterable = None - AsyncIterator = None + __all__.append('AsyncIterable') + __all__.append('AsyncIterator') class Iterable(Generic[T_co], extra=collections_abc.Iterable): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 19:06:10 2016 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Oct 2016 23:06:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328556=3A_updates_to_typing=2Epy_=28add_Coroutine=2C_p?= =?utf-8?b?cm9oaWJpdCBHZW5lcmljW1RdKCkp?= Message-ID: <20161029230610.17396.95699.257387D3@psf.io> https://hg.python.org/cpython/rev/2c2fec17247d changeset: 104804:2c2fec17247d branch: 3.6 parent: 104801:465b345559ea parent: 104803:0201a87d773d user: Guido van Rossum date: Sat Oct 29 16:05:27 2016 -0700 summary: Issue #28556: updates to typing.py (add Coroutine, prohibit Generic[T]()) (3.5->3.6) files: Lib/test/test_typing.py | 23 ++++++++++++++++++++- Lib/typing.py | 31 +++++++++++++++++++++------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -517,6 +517,9 @@ Y[str, str] def test_generic_errors(self): + T = TypeVar('T') + with self.assertRaises(TypeError): + Generic[T]() with self.assertRaises(TypeError): isinstance([], List[int]) with self.assertRaises(TypeError): @@ -1255,7 +1258,7 @@ ASYNCIO_TESTS = """ import asyncio -T_a = TypeVar('T') +T_a = TypeVar('T_a') class AwaitableWrapper(typing.Awaitable[T_a]): @@ -1404,6 +1407,24 @@ g.send(None) # Run foo() till completion, to avoid warning. @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') + def test_coroutine(self): + ns = {} + exec( + "async def foo():\n" + " return\n", + globals(), ns) + foo = ns['foo'] + g = foo() + self.assertIsInstance(g, typing.Coroutine) + with self.assertRaises(TypeError): + isinstance(g, typing.Coroutine[int]) + self.assertNotIsInstance(foo, typing.Coroutine) + try: + g.send(None) + except StopIteration: + pass + + @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') def test_async_iterable(self): base_it = range(10) # type: Iterator[int] it = AsyncIteratorWrapper(base_it) diff --git a/Lib/typing.py b/Lib/typing.py --- a/Lib/typing.py +++ b/Lib/typing.py @@ -29,9 +29,6 @@ # ABCs (from collections.abc). 'AbstractSet', # collections.abc.Set. - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', 'ByteString', 'Container', 'Hashable', @@ -47,6 +44,14 @@ 'Sequence', 'Sized', 'ValuesView', + # The following are added depending on presence + # of their non-generic counterparts in stdlib: + # Awaitable, + # AsyncIterator, + # AsyncIterable, + # Coroutine, + # Collection, + # ContextManager # Structural checks, a.k.a. protocols. 'Reversible', @@ -1104,6 +1109,9 @@ __slots__ = () def __new__(cls, *args, **kwds): + if _geqv(cls, Generic): + raise TypeError("Type Generic cannot be instantiated; " + "it can be used only as a base class") return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) @@ -1639,8 +1647,16 @@ if hasattr(collections_abc, 'Awaitable'): class Awaitable(Generic[T_co], extra=collections_abc.Awaitable): __slots__ = () -else: - Awaitable = None + + __all__.append('Awaitable') + + +if hasattr(collections_abc, 'Coroutine'): + class Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co], + extra=collections_abc.Coroutine): + __slots__ = () + + __all__.append('Coroutine') if hasattr(collections_abc, 'AsyncIterable'): @@ -1652,9 +1668,8 @@ extra=collections_abc.AsyncIterator): __slots__ = () -else: - AsyncIterable = None - AsyncIterator = None + __all__.append('AsyncIterable') + __all__.append('AsyncIterator') class Iterable(Generic[T_co], extra=collections_abc.Iterable): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 19:57:15 2016 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 29 Oct 2016 23:57:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20161029235715.7163.80952.81799E4C@psf.io> https://hg.python.org/cpython/rev/02c620e7a44d changeset: 104807:02c620e7a44d parent: 104805:fe842efbe1ed parent: 104806:32bfc81111b6 user: Raymond Hettinger date: Sat Oct 29 16:57:09 2016 -0700 summary: merge files: Lib/random.py | 7 ++++--- Lib/test/test_random.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -344,10 +344,12 @@ the selections are made with equal probability. """ + random = self.random if cum_weights is None: if weights is None: - choice = self.choice - return [choice(population) for i in range(k)] + _int = int + total = len(population) + return [population[_int(random() * total)] for i in range(k)] else: cum_weights = list(_itertools.accumulate(weights)) elif weights is not None: @@ -355,7 +357,6 @@ if len(cum_weights) != len(population): raise ValueError('The number of weights does not match the population') bisect = _bisect.bisect - random = self.random total = cum_weights[-1] return [population[bisect(cum_weights, random() * total)] for i in range(k)] diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -625,6 +625,22 @@ self.assertTrue(stop < x <= start) self.assertEqual((x+stop)%step, 0) + def test_choices_algorithms(self): + # The various ways of specifing weights should produce the same results + choices = self.gen.choices + n = 13132817 + + self.gen.seed(8675309) + a = self.gen.choices(range(n), k=10000) + + self.gen.seed(8675309) + b = self.gen.choices(range(n), [1]*n, k=10000) + self.assertEqual(a, b) + + self.gen.seed(8675309) + c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000) + self.assertEqual(a, c) + def gamma(z, sqrt2pi=(2.0*pi)**0.5): # Reflection to right half of complex plane if z < 0.5: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 19:57:15 2016 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 29 Oct 2016 23:57:15 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzE4ODQ0?= =?utf-8?q?=3A_Make_the_various_ways_for_specifing_weights_produce_the_sam?= =?utf-8?q?e?= Message-ID: <20161029235715.22316.27290.DCB59628@psf.io> https://hg.python.org/cpython/rev/32bfc81111b6 changeset: 104806:32bfc81111b6 branch: 3.6 parent: 104804:2c2fec17247d user: Raymond Hettinger date: Sat Oct 29 16:55:36 2016 -0700 summary: Issue #18844: Make the various ways for specifing weights produce the same results. files: Lib/random.py | 7 ++++--- Lib/test/test_random.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -344,10 +344,12 @@ the selections are made with equal probability. """ + random = self.random if cum_weights is None: if weights is None: - choice = self.choice - return [choice(population) for i in range(k)] + _int = int + total = len(population) + return [population[_int(random() * total)] for i in range(k)] else: cum_weights = list(_itertools.accumulate(weights)) elif weights is not None: @@ -355,7 +357,6 @@ if len(cum_weights) != len(population): raise ValueError('The number of weights does not match the population') bisect = _bisect.bisect - random = self.random total = cum_weights[-1] return [population[bisect(cum_weights, random() * total)] for i in range(k)] diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -629,6 +629,22 @@ self.assertTrue(stop < x <= start) self.assertEqual((x+stop)%step, 0) + def test_choices_algorithms(self): + # The various ways of specifing weights should produce the same results + choices = self.gen.choices + n = 13132817 + + self.gen.seed(8675309) + a = self.gen.choices(range(n), k=10000) + + self.gen.seed(8675309) + b = self.gen.choices(range(n), [1]*n, k=10000) + self.assertEqual(a, b) + + self.gen.seed(8675309) + c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000) + self.assertEqual(a, c) + def gamma(z, sqrt2pi=(2.0*pi)**0.5): # Reflection to right half of complex plane if z < 0.5: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ - Issue #27275: Fixed implementation of pop() and popitem() methods in subclasses of accelerated OrderedDict. +- Issue #18844: The various ways of specifing weights for random.choices() + now produce the same result sequences. + - Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 20:43:09 2016 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Oct 2016 00:43:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzE4ODQ0?= =?utf-8?q?=3A__Strengthen_tests_to_include_a_case_with_unequal_weighting?= Message-ID: <20161030004309.62869.96188.6F1545E1@psf.io> https://hg.python.org/cpython/rev/09a87b16d5e5 changeset: 104808:09a87b16d5e5 branch: 3.6 parent: 104806:32bfc81111b6 user: Raymond Hettinger date: Sat Oct 29 17:42:36 2016 -0700 summary: Issue #18844: Strengthen tests to include a case with unequal weighting files: Lib/test/test_random.py | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -645,6 +645,23 @@ c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000) self.assertEqual(a, c) + # Amerian Roulette + population = ['Red', 'Black', 'Green'] + weights = [18, 18, 2] + cum_weights = [18, 36, 38] + expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2 + + self.gen.seed(9035768) + a = self.gen.choices(expanded_population, k=10000) + + self.gen.seed(9035768) + b = self.gen.choices(population, weights, k=10000) + self.assertEqual(a, b) + + self.gen.seed(9035768) + c = self.gen.choices(population, cum_weights=cum_weights, k=10000) + self.assertEqual(a, c) + def gamma(z, sqrt2pi=(2.0*pi)**0.5): # Reflection to right half of complex plane if z < 0.5: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Oct 29 20:43:09 2016 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Oct 2016 00:43:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20161030004309.30849.55192.2889525E@psf.io> https://hg.python.org/cpython/rev/73c29ae6564e changeset: 104809:73c29ae6564e parent: 104807:02c620e7a44d parent: 104808:09a87b16d5e5 user: Raymond Hettinger date: Sat Oct 29 17:43:02 2016 -0700 summary: merge files: Lib/test/test_random.py | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -641,6 +641,23 @@ c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000) self.assertEqual(a, c) + # Amerian Roulette + population = ['Red', 'Black', 'Green'] + weights = [18, 18, 2] + cum_weights = [18, 36, 38] + expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2 + + self.gen.seed(9035768) + a = self.gen.choices(expanded_population, k=10000) + + self.gen.seed(9035768) + b = self.gen.choices(population, weights, k=10000) + self.assertEqual(a, b) + + self.gen.seed(9035768) + c = self.gen.choices(population, cum_weights=cum_weights, k=10000) + self.assertEqual(a, c) + def gamma(z, sqrt2pi=(2.0*pi)**0.5): # Reflection to right half of complex plane if z < 0.5: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:15 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:15 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2NjM4?= =?utf-8?q?=3A_Work_around_more_CLI_options_that_can=E2=80=99t_be_linked?= Message-ID: <20161030055015.31195.73990.658095A8@psf.io> https://hg.python.org/cpython/rev/57f4ba6b29bf changeset: 104811:57f4ba6b29bf branch: 3.5 user: Martin Panter date: Sun Oct 30 04:20:23 2016 +0000 summary: Issue #26638: Work around more CLI options that can?t be linked * Cannot seem to link directly to main options from the ?unittest? module, because that module has its own set of options * Mask out linking for options that no longer exist in Python 3 files: Doc/library/unittest.rst | 6 ++++-- Doc/using/cmdline.rst | 1 + Doc/whatsnew/2.2.rst | 2 +- Doc/whatsnew/2.6.rst | 4 ++-- Doc/whatsnew/2.7.rst | 4 ++-- 5 files changed, 10 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 @@ -1972,7 +1972,8 @@ methods ` are also special-cased and, when the warning filters are ``'default'`` or ``'always'``, they will appear only once per-module, in order to avoid too many warning messages. This behavior can - be overridden using the :option:`-Wd` or :option:`-Wa` options and leaving + be overridden using Python's :option:`!-Wd` or :option:`!-Wa` options + (see :ref:`Warning control `) and leaving *warnings* to ``None``. .. versionchanged:: 3.2 @@ -2053,7 +2054,8 @@ The *warnings* argument specifies the :ref:`warning filter ` that should be used while running the tests. If it's not specified, it will - remain ``None`` if a :option:`-W` option is passed to :program:`python`, + remain ``None`` if a :option:`!-W` option is passed to :program:`python` + (see :ref:`Warning control `), otherwise it will be set to ``'default'``. Calling ``main`` actually returns an instance of the ``TestProgram`` class. diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -313,6 +313,7 @@ See also :envvar:`PYTHONVERBOSE`. +.. _using-on-warnings: .. cmdoption:: -W arg Warning control. Python's warning machinery by default prints warning diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -758,7 +758,7 @@ operators. * Python 2.2 supports some command-line arguments for testing whether code will - work with the changed division semantics. Running python with :option:`-Q + work with the changed division semantics. Running python with :option:`!-Q warn` will cause a warning to be issued whenever division is applied to two integers. You can use this to find code that's affected by the change and fix it. By default, Python 2.2 will simply perform classic division without a diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -58,7 +58,7 @@ remaining compatible with existing code by not removing older features or syntax. When it's not possible to do that, Python 2.6 tries to do what it can, adding compatibility functions in a -:mod:`future_builtins` module and a :option:`-3` switch to warn about +:mod:`future_builtins` module and a :option:`!-3` switch to warn about usages that will become unsupported in 3.0. Some significant new packages have been added to the standard library, @@ -116,7 +116,7 @@ compatible with 3.0 can do ``from future_builtins import hex, map`` as necessary. -A new command-line switch, :option:`-3`, enables warnings +A new command-line switch, :option:`!-3`, enables warnings about features that will be removed in Python 3.0. You can run code with this switch to see how much work will be necessary to port code to 3.0. The value of this switch is available diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -198,8 +198,8 @@ * :func:`operator.isCallable` and :func:`operator.sequenceIncludes`, which are not supported in 3.x, now trigger warnings. -* The :option:`-3` switch now automatically - enables the :option:`-Qwarn <-Q>` switch that causes warnings +* The :option:`!-3` switch now automatically + enables the :option:`!-Qwarn` switch that causes warnings about using classic division with integers and long integers. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:16 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI2NjM4?= =?utf-8?q?=3A_Disable_inappropriate_links_to_Python_interpreter_options?= Message-ID: <20161030055016.45304.83599.E6463506@psf.io> https://hg.python.org/cpython/rev/c4b934a77a08 changeset: 104814:c4b934a77a08 branch: 2.7 parent: 104768:27af988f5623 user: Martin Panter date: Sun Oct 30 05:24:45 2016 +0000 summary: Issue #26638: Disable inappropriate links to Python interpreter options files: Doc/library/easydialogs.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/easydialogs.rst b/Doc/library/easydialogs.rst --- a/Doc/library/easydialogs.rst +++ b/Doc/library/easydialogs.rst @@ -90,9 +90,9 @@ +----------------------+------------------------------------------+ | *optstr* format | Command-line format | +======================+==========================================+ - | ``x`` | :option:`-x` (short option) | + | ``x`` | :option:`!-x` (short option) | +----------------------+------------------------------------------+ - | ``x:`` or ``x=`` | :option:`-x` (short option with value) | + | ``x:`` or ``x=`` | :option:`!-x` (short option with value) | +----------------------+------------------------------------------+ | ``xyz`` | :option:`--xyz` (long option) | +----------------------+------------------------------------------+ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:15 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:15 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI2NjM4?= =?utf-8?q?=3A_Mask_undefined_CLI_options_to_defeat_new_Sphinx_warnings?= Message-ID: <20161030055015.114717.55870.9EAF1FD7@psf.io> https://hg.python.org/cpython/rev/307d7568b6ae changeset: 104810:307d7568b6ae branch: 3.5 parent: 104803:0201a87d773d user: Martin Panter date: Sun Oct 30 04:20:17 2016 +0000 summary: Issue #26638: Mask undefined CLI options to defeat new Sphinx warnings files: Doc/distutils/apiref.rst | 32 +++++++------- Doc/distutils/builtdist.rst | 32 +++++++------- Doc/distutils/configfile.rst | 6 +- Doc/distutils/extending.rst | 2 +- Doc/distutils/setupscript.rst | 2 +- Doc/distutils/sourcedist.rst | 12 ++-- Doc/extending/extending.rst | 2 +- Doc/install/index.rst | 50 +++++++++++----------- Doc/library/2to3.rst | 28 ++++++------ Doc/library/ctypes.rst | 4 +- Doc/library/gettext.rst | 2 +- Doc/library/warnings.rst | 6 +- Doc/using/cmdline.rst | 4 +- Doc/whatsnew/2.0.rst | 2 +- Doc/whatsnew/2.1.rst | 2 +- Doc/whatsnew/2.2.rst | 8 +- Doc/whatsnew/2.3.rst | 14 +++--- Doc/whatsnew/2.4.rst | 6 +- Doc/whatsnew/2.5.rst | 6 +- Doc/whatsnew/2.6.rst | 4 +- Doc/whatsnew/2.7.rst | 26 +++++----- Doc/whatsnew/3.0.rst | 2 +- 22 files changed, 126 insertions(+), 126 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -205,7 +205,7 @@ | | to or ``None`` to define it | | | | without a particular value | | | | (equivalent of ``#define FOO`` | | - | | in source or :option:`-DFOO` | | + | | in source or :option:`!-DFOO` | | | | on Unix C compiler command | | | | line) | | +------------------------+--------------------------------+---------------------------+ @@ -319,11 +319,11 @@ .. function:: gen_preprocess_options(macros, include_dirs) - Generate C pre-processor options (:option:`-D`, :option:`!-U`, :option:`!-I`) as + Generate C pre-processor options (:option:`!-D`, :option:`!-U`, :option:`!-I`) as used by at least two types of compilers: the typical Unix compiler and Visual C++. *macros* is the usual thing, a list of 1- or 2-tuples, where ``(name,)`` means undefine (:option:`!-U`) macro *name*, and ``(name, value)`` means define - (:option:`-D`) macro *name* to *value*. *include_dirs* is just a list of + (:option:`!-D`) macro *name* to *value*. *include_dirs* is just a list of directory names to be added to the header file search path (:option:`!-I`). Returns a list of command-line options suitable for either Unix compilers or Visual C++. @@ -359,7 +359,7 @@ .. function:: show_compilers() - Print list of available compilers (used by the :option:`--help-compiler` options + Print list of available compilers (used by the :option:`!--help-compiler` options to :command:`build`, :command:`build_ext`, :command:`build_clib`). @@ -789,15 +789,15 @@ This module provides the :class:`UnixCCompiler` class, a subclass of :class:`CCompiler` that handles the typical Unix-style command-line C compiler: -* macros defined with :option:`-Dname[=value]` - -* macros undefined with :option:`-Uname` - -* include search directories specified with :option:`-Idir` - -* libraries specified with :option:`-llib` - -* library search directories specified with :option:`-Ldir` +* macros defined with :option:`!-Dname[=value]` + +* macros undefined with :option:`!-Uname` + +* include search directories specified with :option:`!-Idir` + +* libraries specified with :option:`!-llib` + +* library search directories specified with :option:`!-Ldir` * compile handled by :program:`cc` (or similar) executable with :option:`!-c` option: compiles :file:`.c` to :file:`.o` @@ -805,7 +805,7 @@ * link static library handled by :program:`ar` command (possibly with :program:`ranlib`) -* link shared library handled by :program:`cc` :option:`-shared` +* link shared library handled by :program:`cc` :option:`!-shared` :mod:`distutils.msvccompiler` --- Microsoft Compiler @@ -1318,8 +1318,8 @@ * options set attributes of a passed-in object -* boolean options can have "negative aliases" --- eg. if :option:`--quiet` is - the "negative alias" of :option:`--verbose`, then :option:`--quiet` on the +* boolean options can have "negative aliases" --- eg. if :option:`!--quiet` is + the "negative alias" of :option:`!--verbose`, then :option:`!--quiet` on the command line sets *verbose* to false. .. function:: fancy_getopt(options, negative_opt, object, args) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -57,7 +57,7 @@ Windows, is far more convenient for users even if your distribution doesn't include any extensions. -The :command:`bdist` command has a :option:`--formats` option, similar to the +The :command:`bdist` command has a :option:`!--formats` option, similar to the :command:`sdist` command, which you can use to select the types of built distribution to generate: for example, :: @@ -123,7 +123,7 @@ requires external :program:`rpm` utility, version 3.0.4 or better (use ``rpm --version`` to find out which version you have) -You don't have to use the :command:`bdist` command with the :option:`--formats` +You don't have to use the :command:`bdist` command with the :option:`!--formats` option; you can also use the command that directly implements the format you're interested in. Some of these :command:`bdist` "sub-commands" actually generate several similar formats; for instance, the :command:`bdist_dumb` command @@ -174,7 +174,7 @@ python setup.py bdist_rpm -or the :command:`bdist` command with the :option:`--format` option:: +or the :command:`bdist` command with the :option:`!--format` option:: python setup.py bdist --formats=rpm @@ -249,7 +249,7 @@ you distribute or package many Python module distributions, you might want to put options that apply to all of them in your personal Distutils configuration file (:file:`~/.pydistutils.cfg`). If you want to temporarily disable -this file, you can pass the :option:`--no-user-cfg` option to :file:`setup.py`. +this file, you can pass the :option:`!--no-user-cfg` option to :file:`setup.py`. There are three steps to building a binary RPM package, all of which are handled automatically by the Distutils: @@ -267,10 +267,10 @@ all three steps are typically bundled together. If you wish, you can separate these three steps. You can use the -:option:`--spec-only` option to make :command:`bdist_rpm` just create the +:option:`!--spec-only` option to make :command:`bdist_rpm` just create the :file:`.spec` file and exit; in this case, the :file:`.spec` file will be written to the "distribution directory"---normally :file:`dist/`, but -customizable with the :option:`--dist-dir` option. (Normally, the :file:`.spec` +customizable with the :option:`!--dist-dir` option. (Normally, the :file:`.spec` file winds up deep in the "build tree," in a temporary directory created by :command:`bdist_rpm`.) @@ -307,7 +307,7 @@ python setup.py bdist_wininst -or the :command:`bdist` command with the :option:`--formats` option:: +or the :command:`bdist` command with the :option:`!--formats` option:: python setup.py bdist --formats=wininst @@ -325,20 +325,20 @@ The installer will try to compile pure modules into :term:`bytecode` after installation on the target system in normal and optimizing mode. If you don't want this to happen for some reason, you can run the :command:`bdist_wininst` command with -the :option:`--no-target-compile` and/or the :option:`--no-target-optimize` +the :option:`!--no-target-compile` and/or the :option:`!--no-target-optimize` option. By default the installer will display the cool "Python Powered" logo when it is run, but you can also supply your own 152x261 bitmap which must be a Windows -:file:`.bmp` file with the :option:`--bitmap` option. +:file:`.bmp` file with the :option:`!--bitmap` option. The installer will also display a large title on the desktop background window when it is run, which is constructed from the name of your distribution and the version number. This can be changed to another text by using the -:option:`--title` option. +:option:`!--title` option. The installer file will be written to the "distribution directory" --- normally -:file:`dist/`, but customizable with the :option:`--dist-dir` option. +:file:`dist/`, but customizable with the :option:`!--dist-dir` option. .. _cross-compile-windows: @@ -350,7 +350,7 @@ installed, you can use a 32bit version of Windows to create 64bit extensions and vice-versa. -To build for an alternate platform, specify the :option:`--plat-name` option +To build for an alternate platform, specify the :option:`!--plat-name` option to the build command. Valid values are currently 'win32', 'win-amd64' and 'win-ia64'. For example, on a 32bit version of Windows, you could execute:: @@ -383,14 +383,14 @@ --------------------------- Starting with Python 2.3, a postinstallation script can be specified with the -:option:`--install-script` option. The basename of the script must be +:option:`!--install-script` option. The basename of the script must be specified, and the script filename must also be listed in the scripts argument to the setup function. This script will be run at installation time on the target system after all the -files have been copied, with ``argv[1]`` set to :option:`-install`, and again at +files have been copied, with ``argv[1]`` set to :option:`!-install`, and again at uninstallation time before the files are removed with ``argv[1]`` set to -:option:`-remove`. +:option:`!-remove`. The installation script runs embedded in the windows installer, every output (``sys.stdout``, ``sys.stderr``) is redirected into a buffer and will be @@ -453,7 +453,7 @@ Vista User Access Control (UAC) =============================== -Starting with Python 2.6, bdist_wininst supports a :option:`--user-access-control` +Starting with Python 2.6, bdist_wininst supports a :option:`!--user-access-control` option. The default is 'none' (meaning no UAC handling is done), and other valid values are 'auto' (meaning prompt for UAC elevation if Python was installed for all users) and 'force' (meaning always prompt for elevation). diff --git a/Doc/distutils/configfile.rst b/Doc/distutils/configfile.rst --- a/Doc/distutils/configfile.rst +++ b/Doc/distutils/configfile.rst @@ -66,7 +66,7 @@ --swig-opts list of SWIG command line options [...] -Note that an option spelled :option:`--foo-bar` on the command-line is spelled +Note that an option spelled :option:`!--foo-bar` on the command-line is spelled ``foo_bar`` in configuration files. .. _distutils-build-ext-inplace: @@ -75,12 +75,12 @@ have an extension :mod:`pkg.ext`, and you want the compiled extension file (:file:`ext.so` on Unix, say) to be put in the same source directory as your pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`--inplace` option on the command-line to ensure this:: +:option:`!--inplace` option on the command-line to ensure this:: python setup.py build_ext --inplace But this requires that you always specify the :command:`build_ext` command -explicitly, and remember to provide :option:`--inplace`. An easier way is to +explicitly, and remember to provide :option:`!--inplace`. An easier way is to "set and forget" this option, by encoding it in :file:`setup.cfg`, the configuration file for this distribution:: diff --git a/Doc/distutils/extending.rst b/Doc/distutils/extending.rst --- a/Doc/distutils/extending.rst +++ b/Doc/distutils/extending.rst @@ -62,7 +62,7 @@ third-party extensions to provide support for additional packaging systems, but the commands can be used for anything distutils commands can be used for. A new configuration option, ``command_packages`` (command-line option -:option:`--command-packages`), can be used to specify additional packages to be +:option:`!--command-packages`), can be used to specify additional packages to be searched for modules implementing commands. Like all distutils options, this can be specified on the command line or in a configuration file. This option can only be set in the ``[global]`` section of a configuration file, or before diff --git a/Doc/distutils/setupscript.rst b/Doc/distutils/setupscript.rst --- a/Doc/distutils/setupscript.rst +++ b/Doc/distutils/setupscript.rst @@ -446,7 +446,7 @@ The only clever feature is that if the first line of the script starts with ``#!`` and contains the word "python", the Distutils will adjust the first line to refer to the current interpreter location. By default, it is replaced with -the current interpreter location. The :option:`--executable` (or :option:`-e`) +the current interpreter location. The :option:`!--executable` (or :option:`!-e`) option will allow the interpreter path to be explicitly overridden. The ``scripts`` option simply is a list of files to be handled in this diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -14,7 +14,7 @@ the current platform. The default format is a gzip'ed tar file (:file:`.tar.gz`) on Unix, and ZIP file on Windows. -You can specify as many formats as you like using the :option:`--formats` +You can specify as many formats as you like using the :option:`!--formats` option, for example:: python setup.py sdist --formats=gztar,zip @@ -147,7 +147,7 @@ :file:`examples/sample?/build`. All of this is done *after* the standard include set, so you can exclude files from the standard set with explicit instructions in the manifest template. (Or, you can use the -:option:`--no-defaults` option to disable the standard set entirely.) There are +:option:`!--no-defaults` option to disable the standard set entirely.) There are several other commands available in the manifest template mini-language; see section :ref:`sdist-cmd`. @@ -166,8 +166,8 @@ future reference, and then used to build the source distribution archive(s). You can disable the default set of included files with the -:option:`--no-defaults` option, and you can disable the standard exclude set -with :option:`--no-prune`. +:option:`!--no-defaults` option, and you can disable the standard exclude set +with :option:`!--no-prune`. Following the Distutils' own manifest template, let's trace how the :command:`sdist` command builds the list of files to include in the Distutils @@ -225,7 +225,7 @@ in) to create the source distribution archive(s) There are a couple of options that modify this behaviour. First, use the -:option:`--no-defaults` and :option:`--no-prune` to disable the standard +:option:`!--no-defaults` and :option:`!--no-prune` to disable the standard "include" and "exclude" sets. Second, you might just want to (re)generate the manifest, but not create a source @@ -233,4 +233,4 @@ python setup.py sdist --manifest-only -:option:`-o` is a shortcut for :option:`--manifest-only`. +:option:`!-o` is a shortcut for :option:`!--manifest-only`. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -886,7 +886,7 @@ :func:`~gc.collect` function), as well as configuration interfaces and the ability to disable the detector at runtime. The cycle detector is considered an optional component; though it is included by default, -it can be disabled at build time using the :option:`--without-cycle-gc` option +it can be disabled at build time using the :option:`!--without-cycle-gc` option to the :program:`configure` script on Unix platforms (including Mac OS X). If the cycle detector is disabled in this way, the :mod:`gc` module will not be available. diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -201,7 +201,7 @@ files to install into a *build directory*. By default, this is :file:`build` under the distribution root; if you're excessively concerned with speed, or want to keep the source tree pristine, you can change the build directory with the -:option:`--build-base` option. For example:: +:option:`!--build-base` option. For example:: python setup.py build --build-base=/path/to/pybuild/foo-1.0 @@ -399,7 +399,7 @@ python setup.py install --home= -where you can supply any directory you like for the :option:`--home` option. On +where you can supply any directory you like for the :option:`!--home` option. On Unix, lazy typists can just type a tilde (``~``); the :command:`install` command will expand this to your home directory:: @@ -410,7 +410,7 @@ :mod:`sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit :data:`sys.path`. -The :option:`--home` option defines the installation base directory. Files are +The :option:`!--home` option defines the installation base directory. Files are installed to the following directories under the installation base as follows: =============== =========================================================== @@ -455,12 +455,12 @@ /usr/local/bin/python setup.py install --prefix=/mnt/@server/export -In either case, the :option:`--prefix` option defines the installation base, and -the :option:`--exec-prefix` option defines the platform-specific installation +In either case, the :option:`!--prefix` option defines the installation base, and +the :option:`!--exec-prefix` option defines the platform-specific installation base, which is used for platform-specific files. (Currently, this just means non-pure module distributions, but could be expanded to C libraries, binary -executables, etc.) If :option:`--exec-prefix` is not supplied, it defaults to -:option:`--prefix`. Files are installed as follows: +executables, etc.) If :option:`!--exec-prefix` is not supplied, it defaults to +:option:`!--prefix`. Files are installed as follows: ================= ========================================================== Type of file Installation directory @@ -472,13 +472,13 @@ C headers :file:`{prefix}/include/python{X.Y}{abiflags}/{distname}` ================= ========================================================== -There is no requirement that :option:`--prefix` or :option:`--exec-prefix` +There is no requirement that :option:`!--prefix` or :option:`!--exec-prefix` actually point to an alternate Python installation; if the directories listed above do not already exist, they are created at installation time. Incidentally, the real reason the prefix scheme is important is simply that a -standard Unix installation uses the prefix scheme, but with :option:`--prefix` -and :option:`--exec-prefix` supplied by Python itself as ``sys.prefix`` and +standard Unix installation uses the prefix scheme, but with :option:`!--prefix` +and :option:`!--exec-prefix` supplied by Python itself as ``sys.prefix`` and ``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme, but every time you run ``python setup.py install`` without any other options, you're using it. @@ -491,7 +491,7 @@ in this way is compatible with the interpreter used to build them. The best way to do this is to ensure that the two interpreters are the same version of Python (possibly different builds, or possibly copies of the same build). (Of course, -if your :option:`--prefix` and :option:`--exec-prefix` don't even point to an +if your :option:`!--prefix` and :option:`!--exec-prefix` don't even point to an alternate Python installation, this is immaterial.) @@ -501,7 +501,7 @@ --------------------------------------------------- Windows has no concept of a user's home directory, and since the standard Python -installation under Windows is simpler than under Unix, the :option:`--prefix` +installation under Windows is simpler than under Unix, the :option:`!--prefix` option has traditionally been used to install additional packages in separate locations on Windows. :: @@ -509,8 +509,8 @@ to install modules to the :file:`\\Temp\\Python` directory on the current drive. -The installation base is defined by the :option:`--prefix` option; the -:option:`--exec-prefix` option is not supported under Windows, which means that +The installation base is defined by the :option:`!--prefix` option; the +:option:`!--exec-prefix` option is not supported under Windows, which means that pure Python modules and extension modules are installed into the same location. Files are installed as follows: @@ -562,7 +562,7 @@ For example, say you're installing a module distribution to your home directory under Unix---but you want scripts to go in :file:`~/scripts` rather than :file:`~/bin`. As you might expect, you can override this directory with the -:option:`--install-scripts` option; in this case, it makes most sense to supply +:option:`!--install-scripts` option; in this case, it makes most sense to supply a relative path, which will be interpreted relative to the installation base directory (your home directory, in this case):: @@ -572,7 +572,7 @@ with a prefix of :file:`/usr/local/python`, so under a standard installation scripts will wind up in :file:`/usr/local/python/bin`. If you want them in :file:`/usr/local/bin` instead, you would supply this absolute directory for the -:option:`--install-scripts` option:: +:option:`!--install-scripts` option:: python setup.py install --install-scripts=/usr/local/bin @@ -932,10 +932,10 @@ to be in Objective C. * *cpparg* is an argument for the C preprocessor, and is anything starting with - :option:`!-I`, :option:`-D`, :option:`!-U` or :option:`-C`. + :option:`!-I`, :option:`!-D`, :option:`!-U` or :option:`!-C`. -* *library* is anything ending in :file:`.a` or beginning with :option:`-l` or - :option:`-L`. +* *library* is anything ending in :file:`.a` or beginning with :option:`!-l` or + :option:`!-L`. If a particular platform requires a special library on your platform, you can add it by editing the :file:`Setup` file and running ``python setup.py build``. @@ -944,20 +944,20 @@ foo foomodule.c must be linked with the math library :file:`libm.a` on your platform, simply add -:option:`-lm` to the line:: +:option:`!-lm` to the line:: foo foomodule.c -lm Arbitrary switches intended for the compiler or the linker can be supplied with -the :option:`-Xcompiler` *arg* and :option:`-Xlinker` *arg* options:: +the :option:`!-Xcompiler` *arg* and :option:`!-Xlinker` *arg* options:: foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm -The next option after :option:`-Xcompiler` and :option:`-Xlinker` will be +The next option after :option:`!-Xcompiler` and :option:`!-Xlinker` will be appended to the proper command line, so in the above example the compiler will -be passed the :option:`-o32` option, and the linker will be passed -:option:`-shared`. If a compiler option requires an argument, you'll have to -supply multiple :option:`-Xcompiler` options; for example, to pass ``-x c++`` +be passed the :option:`!-o32` option, and the linker will be passed +:option:`!-shared`. If a compiler option requires an argument, you'll have to +supply multiple :option:`!-Xcompiler` options; for example, to pass ``-x c++`` the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``. Compiler flags can also be supplied through setting the :envvar:`CFLAGS` diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst --- a/Doc/library/2to3.rst +++ b/Doc/library/2to3.rst @@ -41,8 +41,8 @@ A diff against the original source file is printed. 2to3 can also write the needed modifications right back to the source file. (A backup of the original -file is made unless :option:`-n` is also given.) Writing the changes back is -enabled with the :option:`-w` flag: +file is made unless :option:`!-n` is also given.) Writing the changes back is +enabled with the :option:`!-w` flag: .. code-block:: shell-session @@ -60,7 +60,7 @@ By default, 2to3 runs a set of :ref:`predefined fixers <2to3-fixers>`. The :option:`!-l` flag lists all available fixers. An explicit set of fixers to run -can be given with :option:`-f`. Likewise the :option:`!-x` explicitly disables a +can be given with :option:`!-f`. Likewise the :option:`!-x` explicitly disables a fixer. The following example runs only the ``imports`` and ``has_key`` fixers: .. code-block:: shell-session @@ -100,29 +100,29 @@ cannot always read files containing the print function. When 2to3 detects the presence of the ``from __future__ import print_function`` compiler directive, it modifies its internal grammar to interpret :func:`print` as a function. This -change can also be enabled manually with the :option:`-p` flag. Use -:option:`-p` to run fixers on code that already has had its print statements +change can also be enabled manually with the :option:`!-p` flag. Use +:option:`!-p` to run fixers on code that already has had its print statements converted. -The :option:`-o` or :option:`--output-dir` option allows specification of an +The :option:`!-o` or :option:`!--output-dir` option allows specification of an alternate directory for processed output files to be written to. The -:option:`-n` flag is required when using this as backup files do not make sense +:option:`!-n` flag is required when using this as backup files do not make sense when not overwriting the input files. .. versionadded:: 3.2.3 - The :option:`-o` option was added. + The :option:`!-o` option was added. -The :option:`!-W` or :option:`--write-unchanged-files` flag tells 2to3 to always +The :option:`!-W` or :option:`!--write-unchanged-files` flag tells 2to3 to always write output files even if no changes were required to the file. This is most -useful with :option:`-o` so that an entire Python source tree is copied with +useful with :option:`!-o` so that an entire Python source tree is copied with translation from one directory to another. -This option implies the :option:`-w` flag as it would not make sense otherwise. +This option implies the :option:`!-w` flag as it would not make sense otherwise. .. versionadded:: 3.2.3 The :option:`!-W` flag was added. -The :option:`--add-suffix` option specifies a string to append to all output -filenames. The :option:`-n` flag is required when specifying this as backups +The :option:`!--add-suffix` option specifies a string to append to all output +filenames. The :option:`!-n` flag is required when specifying this as backups are not necessary when writing to different filenames. Example: .. code-block:: shell-session @@ -132,7 +132,7 @@ Will cause a converted file named ``example.py3`` to be written. .. versionadded:: 3.2.3 - The :option:`--add-suffix` option was added. + The :option:`!--add-suffix` option was added. To translate an entire project from one directory tree to another use: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1253,7 +1253,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like *lib*, suffix like ``.so``, ``.dylib`` or version number (this - is the form used for the posix linker option :option:`-l`). If no library can + is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. @@ -1831,7 +1831,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like ``lib``, suffix like ``.so``, ``.dylib`` or version - number (this is the form used for the posix linker option :option:`-l`). If + number (this is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -621,7 +621,7 @@ However, you will need to teach your message extraction program to look for translatable strings marked with :func:`N_`. :program:`xgettext`, :program:`pygettext`, ``pybabel extract``, and :program:`xpot` all -support this through the use of the :option:`-k` command-line switch. +support this through the use of the :option:`!-k` command-line switch. The choice of :func:`N_` here is totally arbitrary; it could have just as easily been :func:`MarkThisStringForTranslation`. diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -267,13 +267,13 @@ Warnings that are only of interest to the developer are ignored by default. As such you should make sure to test your code with typically ignored warnings made visible. You can do this from the command-line by passing :option:`-Wd <-W>` -to the interpreter (this is shorthand for :option:`-W default`). This enables +to the interpreter (this is shorthand for :option:`!-W default`). This enables default handling for all warnings, including those that are ignored by default. To change what action is taken for encountered warnings you simply change what -argument is passed to :option:`-W`, e.g. :option:`-W error`. See the +argument is passed to :option:`-W`, e.g. :option:`!-W error`. See the :option:`-W` flag for more details on what is possible. -To programmatically do the same as :option:`-Wd`, use:: +To programmatically do the same as :option:`!-Wd`, use:: warnings.simplefilter('default') diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -192,7 +192,7 @@ Issue a warning when comparing :class:`bytes` or :class:`bytearray` with :class:`str` or :class:`bytes` with :class:`int`. Issue an error when the - option is given twice (:option:`-bb`). + option is given twice (:option:`!-bb`). .. versionchanged:: 3.5 Affects comparisons of :class:`bytes` with :class:`int`. @@ -308,7 +308,7 @@ Print a message each time a module is initialized, showing the place (filename or built-in module) from which it is loaded. When given twice - (:option:`-vv`), print a message for each file that is checked for when + (:option:`!-vv`), print a message for each file that is checked for when searching for a module. Also provides information on module cleanup at exit. See also :envvar:`PYTHONVERBOSE`. diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -476,7 +476,7 @@ program creates and destroys objects. The detection of cycles can be disabled when Python is compiled, if you can't afford even a tiny speed penalty or suspect that the cycle collection is buggy, by specifying the -:option:`--without-cycle-gc` switch when running the :program:`configure` +:option:`!--without-cycle-gc` switch when running the :program:`configure` script. Several people tackled this problem and contributed to a solution. An early diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -692,7 +692,7 @@ faster than the system :func:`malloc` and have less memory overhead. The allocator uses C's :func:`malloc` function to get large pools of memory, and then fulfills smaller memory requests from these pools. It can be enabled by - providing the :option:`--with-pymalloc` option to the :program:`configure` + providing the :option:`!--with-pymalloc` option to the :program:`configure` script; see :file:`Objects/obmalloc.c` for the implementation details. Authors of C extension modules should test their code with the object allocator diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -779,8 +779,8 @@ Python's Unicode support has been enhanced a bit in 2.2. Unicode strings are usually stored as UCS-2, as 16-bit unsigned integers. Python 2.2 can also be compiled to use UCS-4, 32-bit unsigned integers, as its internal encoding by -supplying :option:`--enable-unicode=ucs4` to the configure script. (It's also -possible to specify :option:`--disable-unicode` to completely disable Unicode +supplying :option:`!--enable-unicode=ucs4` to the configure script. (It's also +possible to specify :option:`!--disable-unicode` to completely disable Unicode support.) When built to use UCS-4 (a "wide Python"), the interpreter can natively handle @@ -979,7 +979,7 @@ output have been corrected. (Contributed by Fred L. Drake, Jr. and Tim Peters.) * The :mod:`socket` module can be compiled to support IPv6; specify the - :option:`--enable-ipv6` option to Python's configure script. (Contributed by + :option:`!--enable-ipv6` option to Python's configure script. (Contributed by Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit @@ -1140,7 +1140,7 @@ in the main Python CVS tree, and many changes have been made to support MacOS X. The most significant change is the ability to build Python as a framework, - enabled by supplying the :option:`--enable-framework` option to the configure + enabled by supplying the :option:`!--enable-framework` option to the configure script when compiling Python. According to Jack Jansen, "This installs a self- contained Python installation plus the OS X framework "glue" into :file:`/Library/Frameworks/Python.framework` (or another location of choice). diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -394,7 +394,7 @@ line-endings. This feature can be disabled when compiling Python by specifying the -:option:`--without-universal-newlines` switch when running Python's +:option:`!--without-universal-newlines` switch when running Python's :program:`configure` script. @@ -1812,9 +1812,9 @@ In 2.1 and 2.2, pymalloc was an experimental feature and wasn't enabled by default; you had to explicitly enable it when compiling Python by providing the -:option:`--with-pymalloc` option to the :program:`configure` script. In 2.3, +:option:`!--with-pymalloc` option to the :program:`configure` script. In 2.3, pymalloc has had further enhancements and is now enabled by default; you'll have -to supply :option:`--without-pymalloc` to disable it. +to supply :option:`!--without-pymalloc` to disable it. This change is transparent to code written in Python; however, pymalloc may expose bugs in C extensions. Authors of C extension modules should test their @@ -1853,7 +1853,7 @@ features to catch memory overwrites and doubled frees in both extension modules and in the interpreter itself. To enable this support, compile a debugging version of the Python interpreter by running :program:`configure` with -:option:`--with-pydebug`. +:option:`!--with-pydebug`. To aid extension writers, a header file :file:`Misc/pymemcompat.h` is distributed with the source to Python 2.3 that allows Python extensions to use @@ -1879,11 +1879,11 @@ * The cycle detection implementation used by the garbage collection has proven to be stable, so it's now been made mandatory. You can no longer compile Python - without it, and the :option:`--with-cycle-gc` switch to :program:`configure` has + without it, and the :option:`!--with-cycle-gc` switch to :program:`configure` has been removed. * Python can now optionally be built as a shared library - (:file:`libpython2.3.so`) by supplying :option:`--enable-shared` when running + (:file:`libpython2.3.so`) by supplying :option:`!--enable-shared` when running Python's :program:`configure` script. (Contributed by Ondrej Palkovsky.) * The :c:macro:`DL_EXPORT` and :c:macro:`DL_IMPORT` macros are now deprecated. @@ -1892,7 +1892,7 @@ generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros. * The interpreter can be compiled without any docstrings for the built-in - functions and modules by supplying :option:`--without-doc-strings` to the + functions and modules by supplying :option:`!--without-doc-strings` to the :program:`configure` script. This makes the Python executable about 10% smaller, but will also mean that you can't get help for Python's built-ins. (Contributed by Gustavo Niemeyer.) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1483,10 +1483,10 @@ * Python can now be built with additional profiling for the interpreter itself, intended as an aid to people developing the Python core. Providing - :option:`--enable-profiling` to the :program:`configure` script will let you + :option:`!--enable-profiling` to the :program:`configure` script will let you profile the interpreter with :program:`gprof`, and providing the - :option:`--with-tsc` switch enables profiling using the Pentium's Time-Stamp- - Counter register. Note that the :option:`--with-tsc` switch is slightly + :option:`!--with-tsc` switch enables profiling using the Pentium's Time-Stamp- + Counter register. Note that the :option:`!--with-tsc` switch is slightly misnamed, because the profiling feature also works on the PowerPC platform, though that processor architecture doesn't call that register "the TSC register". (Contributed by Jeremy Hylton.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -236,7 +236,7 @@ Before a package can be uploaded, you must be able to build a distribution using the :command:`sdist` Distutils command. Once that works, you can run ``python setup.py upload`` to add your package to the PyPI archive. Optionally you can -GPG-sign the package by supplying the :option:`--sign` and :option:`--identity` +GPG-sign the package by supplying the :option:`!--sign` and :option:`!--identity` options. Package uploading was implemented by Martin von L?wis and Richard Jones. @@ -1639,7 +1639,7 @@ * The :mod:`webbrowser` module received a number of enhancements. It's now usable as a script with ``python -m webbrowser``, taking a URL as the argument; - there are a number of switches to control the behaviour (:option:`-n` for a new + there are a number of switches to control the behaviour (:option:`!-n` for a new browser window, :option:`!-t` for a new tab). New module-level functions, :func:`open_new` and :func:`open_new_tab`, were added to support this. The module's :func:`open` function supports an additional feature, an *autoraise* @@ -2209,7 +2209,7 @@ * MacOS X (10.3 and higher): dynamic loading of modules now uses the :c:func:`dlopen` function instead of MacOS-specific functions. -* MacOS X: an :option:`--enable-universalsdk` switch was added to the +* MacOS X: an :option:`!--enable-universalsdk` switch was added to the :program:`configure` script that compiles the interpreter as a universal binary able to run on both PowerPC and Intel processors. (Contributed by Ronald Oussoren; :issue:`2573`.) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2992,7 +2992,7 @@ * On Mac OS X, Python 2.6 can be compiled as a 4-way universal build. The :program:`configure` script - can take a :option:`--with-universal-archs=[32-bit|64-bit|all]` + can take a :option:`!--with-universal-archs=[32-bit|64-bit|all]` switch, controlling whether the binaries are built for 32-bit architectures (x86, PowerPC), 64-bit (x86-64 and PPC-64), or both. (Contributed by Ronald Oussoren.) @@ -3147,7 +3147,7 @@ * When compiling a framework build of Python, you can now specify the framework name to be used by providing the - :option:`--with-framework-name=` option to the + :option:`!--with-framework-name=` option to the :program:`configure` script. * The :mod:`macfs` module has been removed. This in turn required the diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -390,7 +390,7 @@ args = parser.parse_args() print args.__dict__ -Unless you override it, :option:`-h` and :option:`--help` switches +Unless you override it, :option:`!-h` and :option:`!--help` switches are automatically added, and produce neatly formatted output:: -> ./python.exe argparse-example.py --help @@ -960,7 +960,7 @@ benchmark results on 32-bit machines have been mixed. Therefore, the default is to use base 2**30 on 64-bit machines and base 2**15 on 32-bit machines; on Unix, there's a new configure option - :option:`--enable-big-digits` that can be used to override this default. + :option:`!--enable-big-digits` that can be used to override this default. Apart from the performance improvements this change should be invisible to end users, with one exception: for testing and @@ -1844,12 +1844,12 @@ The :func:`~unittest.main` function supports some other new options: -* :option:`-b ` or :option:`--buffer` will buffer the standard output +* :option:`-b ` or :option:`!--buffer` will buffer the standard output and standard error streams during each test. If the test passes, any resulting output will be discarded; on failure, the buffered output will be displayed. -* :option:`-c ` or :option:`--catch` will cause the control-C interrupt +* :option:`-c ` or :option:`!--catch` will cause the control-C interrupt to be handled more gracefully. Instead of interrupting the test process immediately, the currently running test will be completed and then the partial results up to the interruption will be reported. @@ -1863,7 +1863,7 @@ :func:`~unittest.removeHandler` decorator that can be used to mark tests that should have the control-C handling disabled. -* :option:`-f ` or :option:`--failfast` makes +* :option:`-f ` or :option:`!--failfast` makes test execution stop immediately when a test fails instead of continuing to execute further tests. (Suggested by Cliff Dyer and implemented by Michael Foord; :issue:`8074`.) @@ -2238,19 +2238,19 @@ with ``Py``, or with ``_ctypes``. (Implemented by Thomas Heller; :issue:`3102`.) -* New configure option: the :option:`--with-system-expat` switch allows +* New configure option: the :option:`!--with-system-expat` switch allows building the :mod:`pyexpat` module to use the system Expat library. (Contributed by Arfrever Frehtes Taifersar Arahesis; :issue:`7609`.) * New configure option: the - :option:`--with-valgrind` option will now disable the pymalloc + :option:`!--with-valgrind` option will now disable the pymalloc allocator, which is difficult for the Valgrind memory-error detector to analyze correctly. Valgrind will therefore be better at detecting memory leaks and overruns. (Contributed by James Henstridge; :issue:`2422`.) * New configure option: you can now supply an empty string to - :option:`--with-dbmliborder=` in order to disable all of the various + :option:`!--with-dbmliborder=` in order to disable all of the various DBM modules. (Added by Arfrever Frehtes Taifersar Arahesis; :issue:`6491`.) @@ -2397,19 +2397,19 @@ renamed, moved, or is accessed through different paths. (Patch by Ziga Seilnacht and Jean-Paul Calderone; :issue:`1180193`.) -* The :file:`regrtest.py` script now takes a :option:`--randseed=` +* The :file:`regrtest.py` script now takes a :option:`!--randseed=` switch that takes an integer that will be used as the random seed - for the :option:`-r` option that executes tests in random order. - The :option:`-r` option also reports the seed that was used + for the :option:`!-r` option that executes tests in random order. + The :option:`!-r` option also reports the seed that was used (Added by Collin Winter.) -* Another :file:`regrtest.py` switch is :option:`-j`, which +* Another :file:`regrtest.py` switch is :option:`!-j`, which takes an integer specifying how many tests run in parallel. This allows reducing the total runtime on multi-core machines. This option is compatible with several other options, including the :option:`!-R` switch which is known to produce long runtimes. (Added by Antoine Pitrou, :issue:`6152`.) This can also be used - with a new :option:`-F` switch that runs selected tests in a loop + with a new :option:`!-F` switch that runs selected tests in a loop until they fail. (Added by Antoine Pitrou; :issue:`7312`.) * When executed as a script, the :file:`py_compile.py` module now diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -904,7 +904,7 @@ port from Python 2.x to Python 2.(x+1). Make sure all your tests pass. -2. (Still using 2.6:) Turn on the :option:`-3` command line switch. +2. (Still using 2.6:) Turn on the :option:`!-3` command line switch. This enables warnings about features that will be removed (or change) in 3.0. Run your test suite again, and fix code that you get warnings about until there are no warnings left, and all your -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:16 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2326638=3A_Merge_option_warning_fixes_from_3=2E5_into_3?= =?utf-8?q?=2E6?= Message-ID: <20161030055015.31120.71414.0156BF23@psf.io> https://hg.python.org/cpython/rev/a0d272fbc7de changeset: 104812:a0d272fbc7de branch: 3.6 parent: 104808:09a87b16d5e5 parent: 104811:57f4ba6b29bf user: Martin Panter date: Sun Oct 30 04:21:23 2016 +0000 summary: Issue #26638: Merge option warning fixes from 3.5 into 3.6 files: Doc/distutils/apiref.rst | 32 +++++++------- Doc/distutils/builtdist.rst | 32 +++++++------- Doc/distutils/configfile.rst | 6 +- Doc/distutils/extending.rst | 2 +- Doc/distutils/setupscript.rst | 2 +- Doc/distutils/sourcedist.rst | 12 ++-- Doc/extending/extending.rst | 2 +- Doc/install/index.rst | 50 +++++++++++----------- Doc/library/2to3.rst | 28 ++++++------ Doc/library/ctypes.rst | 4 +- Doc/library/gettext.rst | 2 +- Doc/library/unittest.rst | 6 +- Doc/library/warnings.rst | 6 +- Doc/using/cmdline.rst | 5 +- Doc/whatsnew/2.0.rst | 2 +- Doc/whatsnew/2.1.rst | 2 +- Doc/whatsnew/2.2.rst | 10 ++-- Doc/whatsnew/2.3.rst | 14 +++--- Doc/whatsnew/2.4.rst | 6 +- Doc/whatsnew/2.5.rst | 6 +- Doc/whatsnew/2.6.rst | 8 +- Doc/whatsnew/2.7.rst | 30 ++++++------ Doc/whatsnew/3.0.rst | 2 +- 23 files changed, 136 insertions(+), 133 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -205,7 +205,7 @@ | | to or ``None`` to define it | | | | without a particular value | | | | (equivalent of ``#define FOO`` | | - | | in source or :option:`-DFOO` | | + | | in source or :option:`!-DFOO` | | | | on Unix C compiler command | | | | line) | | +------------------------+--------------------------------+---------------------------+ @@ -319,11 +319,11 @@ .. function:: gen_preprocess_options(macros, include_dirs) - Generate C pre-processor options (:option:`-D`, :option:`!-U`, :option:`!-I`) as + Generate C pre-processor options (:option:`!-D`, :option:`!-U`, :option:`!-I`) as used by at least two types of compilers: the typical Unix compiler and Visual C++. *macros* is the usual thing, a list of 1- or 2-tuples, where ``(name,)`` means undefine (:option:`!-U`) macro *name*, and ``(name, value)`` means define - (:option:`-D`) macro *name* to *value*. *include_dirs* is just a list of + (:option:`!-D`) macro *name* to *value*. *include_dirs* is just a list of directory names to be added to the header file search path (:option:`!-I`). Returns a list of command-line options suitable for either Unix compilers or Visual C++. @@ -359,7 +359,7 @@ .. function:: show_compilers() - Print list of available compilers (used by the :option:`--help-compiler` options + Print list of available compilers (used by the :option:`!--help-compiler` options to :command:`build`, :command:`build_ext`, :command:`build_clib`). @@ -789,15 +789,15 @@ This module provides the :class:`UnixCCompiler` class, a subclass of :class:`CCompiler` that handles the typical Unix-style command-line C compiler: -* macros defined with :option:`-Dname[=value]` - -* macros undefined with :option:`-Uname` - -* include search directories specified with :option:`-Idir` - -* libraries specified with :option:`-llib` - -* library search directories specified with :option:`-Ldir` +* macros defined with :option:`!-Dname[=value]` + +* macros undefined with :option:`!-Uname` + +* include search directories specified with :option:`!-Idir` + +* libraries specified with :option:`!-llib` + +* library search directories specified with :option:`!-Ldir` * compile handled by :program:`cc` (or similar) executable with :option:`!-c` option: compiles :file:`.c` to :file:`.o` @@ -805,7 +805,7 @@ * link static library handled by :program:`ar` command (possibly with :program:`ranlib`) -* link shared library handled by :program:`cc` :option:`-shared` +* link shared library handled by :program:`cc` :option:`!-shared` :mod:`distutils.msvccompiler` --- Microsoft Compiler @@ -1318,8 +1318,8 @@ * options set attributes of a passed-in object -* boolean options can have "negative aliases" --- eg. if :option:`--quiet` is - the "negative alias" of :option:`--verbose`, then :option:`--quiet` on the +* boolean options can have "negative aliases" --- eg. if :option:`!--quiet` is + the "negative alias" of :option:`!--verbose`, then :option:`!--quiet` on the command line sets *verbose* to false. .. function:: fancy_getopt(options, negative_opt, object, args) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -57,7 +57,7 @@ Windows, is far more convenient for users even if your distribution doesn't include any extensions. -The :command:`bdist` command has a :option:`--formats` option, similar to the +The :command:`bdist` command has a :option:`!--formats` option, similar to the :command:`sdist` command, which you can use to select the types of built distribution to generate: for example, :: @@ -123,7 +123,7 @@ requires external :program:`rpm` utility, version 3.0.4 or better (use ``rpm --version`` to find out which version you have) -You don't have to use the :command:`bdist` command with the :option:`--formats` +You don't have to use the :command:`bdist` command with the :option:`!--formats` option; you can also use the command that directly implements the format you're interested in. Some of these :command:`bdist` "sub-commands" actually generate several similar formats; for instance, the :command:`bdist_dumb` command @@ -174,7 +174,7 @@ python setup.py bdist_rpm -or the :command:`bdist` command with the :option:`--format` option:: +or the :command:`bdist` command with the :option:`!--format` option:: python setup.py bdist --formats=rpm @@ -249,7 +249,7 @@ you distribute or package many Python module distributions, you might want to put options that apply to all of them in your personal Distutils configuration file (:file:`~/.pydistutils.cfg`). If you want to temporarily disable -this file, you can pass the :option:`--no-user-cfg` option to :file:`setup.py`. +this file, you can pass the :option:`!--no-user-cfg` option to :file:`setup.py`. There are three steps to building a binary RPM package, all of which are handled automatically by the Distutils: @@ -267,10 +267,10 @@ all three steps are typically bundled together. If you wish, you can separate these three steps. You can use the -:option:`--spec-only` option to make :command:`bdist_rpm` just create the +:option:`!--spec-only` option to make :command:`bdist_rpm` just create the :file:`.spec` file and exit; in this case, the :file:`.spec` file will be written to the "distribution directory"---normally :file:`dist/`, but -customizable with the :option:`--dist-dir` option. (Normally, the :file:`.spec` +customizable with the :option:`!--dist-dir` option. (Normally, the :file:`.spec` file winds up deep in the "build tree," in a temporary directory created by :command:`bdist_rpm`.) @@ -307,7 +307,7 @@ python setup.py bdist_wininst -or the :command:`bdist` command with the :option:`--formats` option:: +or the :command:`bdist` command with the :option:`!--formats` option:: python setup.py bdist --formats=wininst @@ -325,20 +325,20 @@ The installer will try to compile pure modules into :term:`bytecode` after installation on the target system in normal and optimizing mode. If you don't want this to happen for some reason, you can run the :command:`bdist_wininst` command with -the :option:`--no-target-compile` and/or the :option:`--no-target-optimize` +the :option:`!--no-target-compile` and/or the :option:`!--no-target-optimize` option. By default the installer will display the cool "Python Powered" logo when it is run, but you can also supply your own 152x261 bitmap which must be a Windows -:file:`.bmp` file with the :option:`--bitmap` option. +:file:`.bmp` file with the :option:`!--bitmap` option. The installer will also display a large title on the desktop background window when it is run, which is constructed from the name of your distribution and the version number. This can be changed to another text by using the -:option:`--title` option. +:option:`!--title` option. The installer file will be written to the "distribution directory" --- normally -:file:`dist/`, but customizable with the :option:`--dist-dir` option. +:file:`dist/`, but customizable with the :option:`!--dist-dir` option. .. _cross-compile-windows: @@ -350,7 +350,7 @@ installed, you can use a 32bit version of Windows to create 64bit extensions and vice-versa. -To build for an alternate platform, specify the :option:`--plat-name` option +To build for an alternate platform, specify the :option:`!--plat-name` option to the build command. Valid values are currently 'win32', 'win-amd64' and 'win-ia64'. For example, on a 32bit version of Windows, you could execute:: @@ -383,14 +383,14 @@ --------------------------- Starting with Python 2.3, a postinstallation script can be specified with the -:option:`--install-script` option. The basename of the script must be +:option:`!--install-script` option. The basename of the script must be specified, and the script filename must also be listed in the scripts argument to the setup function. This script will be run at installation time on the target system after all the -files have been copied, with ``argv[1]`` set to :option:`-install`, and again at +files have been copied, with ``argv[1]`` set to :option:`!-install`, and again at uninstallation time before the files are removed with ``argv[1]`` set to -:option:`-remove`. +:option:`!-remove`. The installation script runs embedded in the windows installer, every output (``sys.stdout``, ``sys.stderr``) is redirected into a buffer and will be @@ -453,7 +453,7 @@ Vista User Access Control (UAC) =============================== -Starting with Python 2.6, bdist_wininst supports a :option:`--user-access-control` +Starting with Python 2.6, bdist_wininst supports a :option:`!--user-access-control` option. The default is 'none' (meaning no UAC handling is done), and other valid values are 'auto' (meaning prompt for UAC elevation if Python was installed for all users) and 'force' (meaning always prompt for elevation). diff --git a/Doc/distutils/configfile.rst b/Doc/distutils/configfile.rst --- a/Doc/distutils/configfile.rst +++ b/Doc/distutils/configfile.rst @@ -66,7 +66,7 @@ --swig-opts list of SWIG command line options [...] -Note that an option spelled :option:`--foo-bar` on the command-line is spelled +Note that an option spelled :option:`!--foo-bar` on the command-line is spelled ``foo_bar`` in configuration files. .. _distutils-build-ext-inplace: @@ -75,12 +75,12 @@ have an extension :mod:`pkg.ext`, and you want the compiled extension file (:file:`ext.so` on Unix, say) to be put in the same source directory as your pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`--inplace` option on the command-line to ensure this:: +:option:`!--inplace` option on the command-line to ensure this:: python setup.py build_ext --inplace But this requires that you always specify the :command:`build_ext` command -explicitly, and remember to provide :option:`--inplace`. An easier way is to +explicitly, and remember to provide :option:`!--inplace`. An easier way is to "set and forget" this option, by encoding it in :file:`setup.cfg`, the configuration file for this distribution:: diff --git a/Doc/distutils/extending.rst b/Doc/distutils/extending.rst --- a/Doc/distutils/extending.rst +++ b/Doc/distutils/extending.rst @@ -62,7 +62,7 @@ third-party extensions to provide support for additional packaging systems, but the commands can be used for anything distutils commands can be used for. A new configuration option, ``command_packages`` (command-line option -:option:`--command-packages`), can be used to specify additional packages to be +:option:`!--command-packages`), can be used to specify additional packages to be searched for modules implementing commands. Like all distutils options, this can be specified on the command line or in a configuration file. This option can only be set in the ``[global]`` section of a configuration file, or before diff --git a/Doc/distutils/setupscript.rst b/Doc/distutils/setupscript.rst --- a/Doc/distutils/setupscript.rst +++ b/Doc/distutils/setupscript.rst @@ -446,7 +446,7 @@ The only clever feature is that if the first line of the script starts with ``#!`` and contains the word "python", the Distutils will adjust the first line to refer to the current interpreter location. By default, it is replaced with -the current interpreter location. The :option:`--executable` (or :option:`-e`) +the current interpreter location. The :option:`!--executable` (or :option:`!-e`) option will allow the interpreter path to be explicitly overridden. The ``scripts`` option simply is a list of files to be handled in this diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -14,7 +14,7 @@ the current platform. The default format is a gzip'ed tar file (:file:`.tar.gz`) on Unix, and ZIP file on Windows. -You can specify as many formats as you like using the :option:`--formats` +You can specify as many formats as you like using the :option:`!--formats` option, for example:: python setup.py sdist --formats=gztar,zip @@ -147,7 +147,7 @@ :file:`examples/sample?/build`. All of this is done *after* the standard include set, so you can exclude files from the standard set with explicit instructions in the manifest template. (Or, you can use the -:option:`--no-defaults` option to disable the standard set entirely.) There are +:option:`!--no-defaults` option to disable the standard set entirely.) There are several other commands available in the manifest template mini-language; see section :ref:`sdist-cmd`. @@ -166,8 +166,8 @@ future reference, and then used to build the source distribution archive(s). You can disable the default set of included files with the -:option:`--no-defaults` option, and you can disable the standard exclude set -with :option:`--no-prune`. +:option:`!--no-defaults` option, and you can disable the standard exclude set +with :option:`!--no-prune`. Following the Distutils' own manifest template, let's trace how the :command:`sdist` command builds the list of files to include in the Distutils @@ -225,7 +225,7 @@ in) to create the source distribution archive(s) There are a couple of options that modify this behaviour. First, use the -:option:`--no-defaults` and :option:`--no-prune` to disable the standard +:option:`!--no-defaults` and :option:`!--no-prune` to disable the standard "include" and "exclude" sets. Second, you might just want to (re)generate the manifest, but not create a source @@ -233,4 +233,4 @@ python setup.py sdist --manifest-only -:option:`-o` is a shortcut for :option:`--manifest-only`. +:option:`!-o` is a shortcut for :option:`!--manifest-only`. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -886,7 +886,7 @@ :func:`~gc.collect` function), as well as configuration interfaces and the ability to disable the detector at runtime. The cycle detector is considered an optional component; though it is included by default, -it can be disabled at build time using the :option:`--without-cycle-gc` option +it can be disabled at build time using the :option:`!--without-cycle-gc` option to the :program:`configure` script on Unix platforms (including Mac OS X). If the cycle detector is disabled in this way, the :mod:`gc` module will not be available. diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -201,7 +201,7 @@ files to install into a *build directory*. By default, this is :file:`build` under the distribution root; if you're excessively concerned with speed, or want to keep the source tree pristine, you can change the build directory with the -:option:`--build-base` option. For example:: +:option:`!--build-base` option. For example:: python setup.py build --build-base=/path/to/pybuild/foo-1.0 @@ -399,7 +399,7 @@ python setup.py install --home= -where you can supply any directory you like for the :option:`--home` option. On +where you can supply any directory you like for the :option:`!--home` option. On Unix, lazy typists can just type a tilde (``~``); the :command:`install` command will expand this to your home directory:: @@ -410,7 +410,7 @@ :mod:`sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit :data:`sys.path`. -The :option:`--home` option defines the installation base directory. Files are +The :option:`!--home` option defines the installation base directory. Files are installed to the following directories under the installation base as follows: =============== =========================================================== @@ -455,12 +455,12 @@ /usr/local/bin/python setup.py install --prefix=/mnt/@server/export -In either case, the :option:`--prefix` option defines the installation base, and -the :option:`--exec-prefix` option defines the platform-specific installation +In either case, the :option:`!--prefix` option defines the installation base, and +the :option:`!--exec-prefix` option defines the platform-specific installation base, which is used for platform-specific files. (Currently, this just means non-pure module distributions, but could be expanded to C libraries, binary -executables, etc.) If :option:`--exec-prefix` is not supplied, it defaults to -:option:`--prefix`. Files are installed as follows: +executables, etc.) If :option:`!--exec-prefix` is not supplied, it defaults to +:option:`!--prefix`. Files are installed as follows: ================= ========================================================== Type of file Installation directory @@ -472,13 +472,13 @@ C headers :file:`{prefix}/include/python{X.Y}{abiflags}/{distname}` ================= ========================================================== -There is no requirement that :option:`--prefix` or :option:`--exec-prefix` +There is no requirement that :option:`!--prefix` or :option:`!--exec-prefix` actually point to an alternate Python installation; if the directories listed above do not already exist, they are created at installation time. Incidentally, the real reason the prefix scheme is important is simply that a -standard Unix installation uses the prefix scheme, but with :option:`--prefix` -and :option:`--exec-prefix` supplied by Python itself as ``sys.prefix`` and +standard Unix installation uses the prefix scheme, but with :option:`!--prefix` +and :option:`!--exec-prefix` supplied by Python itself as ``sys.prefix`` and ``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme, but every time you run ``python setup.py install`` without any other options, you're using it. @@ -491,7 +491,7 @@ in this way is compatible with the interpreter used to build them. The best way to do this is to ensure that the two interpreters are the same version of Python (possibly different builds, or possibly copies of the same build). (Of course, -if your :option:`--prefix` and :option:`--exec-prefix` don't even point to an +if your :option:`!--prefix` and :option:`!--exec-prefix` don't even point to an alternate Python installation, this is immaterial.) @@ -501,7 +501,7 @@ --------------------------------------------------- Windows has no concept of a user's home directory, and since the standard Python -installation under Windows is simpler than under Unix, the :option:`--prefix` +installation under Windows is simpler than under Unix, the :option:`!--prefix` option has traditionally been used to install additional packages in separate locations on Windows. :: @@ -509,8 +509,8 @@ to install modules to the :file:`\\Temp\\Python` directory on the current drive. -The installation base is defined by the :option:`--prefix` option; the -:option:`--exec-prefix` option is not supported under Windows, which means that +The installation base is defined by the :option:`!--prefix` option; the +:option:`!--exec-prefix` option is not supported under Windows, which means that pure Python modules and extension modules are installed into the same location. Files are installed as follows: @@ -562,7 +562,7 @@ For example, say you're installing a module distribution to your home directory under Unix---but you want scripts to go in :file:`~/scripts` rather than :file:`~/bin`. As you might expect, you can override this directory with the -:option:`--install-scripts` option; in this case, it makes most sense to supply +:option:`!--install-scripts` option; in this case, it makes most sense to supply a relative path, which will be interpreted relative to the installation base directory (your home directory, in this case):: @@ -572,7 +572,7 @@ with a prefix of :file:`/usr/local/python`, so under a standard installation scripts will wind up in :file:`/usr/local/python/bin`. If you want them in :file:`/usr/local/bin` instead, you would supply this absolute directory for the -:option:`--install-scripts` option:: +:option:`!--install-scripts` option:: python setup.py install --install-scripts=/usr/local/bin @@ -932,10 +932,10 @@ to be in Objective C. * *cpparg* is an argument for the C preprocessor, and is anything starting with - :option:`!-I`, :option:`-D`, :option:`!-U` or :option:`-C`. + :option:`!-I`, :option:`!-D`, :option:`!-U` or :option:`!-C`. -* *library* is anything ending in :file:`.a` or beginning with :option:`-l` or - :option:`-L`. +* *library* is anything ending in :file:`.a` or beginning with :option:`!-l` or + :option:`!-L`. If a particular platform requires a special library on your platform, you can add it by editing the :file:`Setup` file and running ``python setup.py build``. @@ -944,20 +944,20 @@ foo foomodule.c must be linked with the math library :file:`libm.a` on your platform, simply add -:option:`-lm` to the line:: +:option:`!-lm` to the line:: foo foomodule.c -lm Arbitrary switches intended for the compiler or the linker can be supplied with -the :option:`-Xcompiler` *arg* and :option:`-Xlinker` *arg* options:: +the :option:`!-Xcompiler` *arg* and :option:`!-Xlinker` *arg* options:: foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm -The next option after :option:`-Xcompiler` and :option:`-Xlinker` will be +The next option after :option:`!-Xcompiler` and :option:`!-Xlinker` will be appended to the proper command line, so in the above example the compiler will -be passed the :option:`-o32` option, and the linker will be passed -:option:`-shared`. If a compiler option requires an argument, you'll have to -supply multiple :option:`-Xcompiler` options; for example, to pass ``-x c++`` +be passed the :option:`!-o32` option, and the linker will be passed +:option:`!-shared`. If a compiler option requires an argument, you'll have to +supply multiple :option:`!-Xcompiler` options; for example, to pass ``-x c++`` the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``. Compiler flags can also be supplied through setting the :envvar:`CFLAGS` diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst --- a/Doc/library/2to3.rst +++ b/Doc/library/2to3.rst @@ -41,8 +41,8 @@ A diff against the original source file is printed. 2to3 can also write the needed modifications right back to the source file. (A backup of the original -file is made unless :option:`-n` is also given.) Writing the changes back is -enabled with the :option:`-w` flag: +file is made unless :option:`!-n` is also given.) Writing the changes back is +enabled with the :option:`!-w` flag: .. code-block:: shell-session @@ -60,7 +60,7 @@ By default, 2to3 runs a set of :ref:`predefined fixers <2to3-fixers>`. The :option:`!-l` flag lists all available fixers. An explicit set of fixers to run -can be given with :option:`-f`. Likewise the :option:`!-x` explicitly disables a +can be given with :option:`!-f`. Likewise the :option:`!-x` explicitly disables a fixer. The following example runs only the ``imports`` and ``has_key`` fixers: .. code-block:: shell-session @@ -100,29 +100,29 @@ cannot always read files containing the print function. When 2to3 detects the presence of the ``from __future__ import print_function`` compiler directive, it modifies its internal grammar to interpret :func:`print` as a function. This -change can also be enabled manually with the :option:`-p` flag. Use -:option:`-p` to run fixers on code that already has had its print statements +change can also be enabled manually with the :option:`!-p` flag. Use +:option:`!-p` to run fixers on code that already has had its print statements converted. -The :option:`-o` or :option:`--output-dir` option allows specification of an +The :option:`!-o` or :option:`!--output-dir` option allows specification of an alternate directory for processed output files to be written to. The -:option:`-n` flag is required when using this as backup files do not make sense +:option:`!-n` flag is required when using this as backup files do not make sense when not overwriting the input files. .. versionadded:: 3.2.3 - The :option:`-o` option was added. + The :option:`!-o` option was added. -The :option:`!-W` or :option:`--write-unchanged-files` flag tells 2to3 to always +The :option:`!-W` or :option:`!--write-unchanged-files` flag tells 2to3 to always write output files even if no changes were required to the file. This is most -useful with :option:`-o` so that an entire Python source tree is copied with +useful with :option:`!-o` so that an entire Python source tree is copied with translation from one directory to another. -This option implies the :option:`-w` flag as it would not make sense otherwise. +This option implies the :option:`!-w` flag as it would not make sense otherwise. .. versionadded:: 3.2.3 The :option:`!-W` flag was added. -The :option:`--add-suffix` option specifies a string to append to all output -filenames. The :option:`-n` flag is required when specifying this as backups +The :option:`!--add-suffix` option specifies a string to append to all output +filenames. The :option:`!-n` flag is required when specifying this as backups are not necessary when writing to different filenames. Example: .. code-block:: shell-session @@ -132,7 +132,7 @@ Will cause a converted file named ``example.py3`` to be written. .. versionadded:: 3.2.3 - The :option:`--add-suffix` option was added. + The :option:`!--add-suffix` option was added. To translate an entire project from one directory tree to another use: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1254,7 +1254,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like *lib*, suffix like ``.so``, ``.dylib`` or version number (this - is the form used for the posix linker option :option:`-l`). If no library can + is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. @@ -1838,7 +1838,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like ``lib``, suffix like ``.so``, ``.dylib`` or version - number (this is the form used for the posix linker option :option:`-l`). If + number (this is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -621,7 +621,7 @@ However, you will need to teach your message extraction program to look for translatable strings marked with :func:`N_`. :program:`xgettext`, :program:`pygettext`, ``pybabel extract``, and :program:`xpot` all -support this through the use of the :option:`-k` command-line switch. +support this through the use of the :option:`!-k` command-line switch. The choice of :func:`N_` here is totally arbitrary; it could have just as easily been :func:`MarkThisStringForTranslation`. diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1972,7 +1972,8 @@ methods ` are also special-cased and, when the warning filters are ``'default'`` or ``'always'``, they will appear only once per-module, in order to avoid too many warning messages. This behavior can - be overridden using the :option:`-Wd` or :option:`-Wa` options and leaving + be overridden using Python's :option:`!-Wd` or :option:`!-Wa` options + (see :ref:`Warning control `) and leaving *warnings* to ``None``. .. versionchanged:: 3.2 @@ -2053,7 +2054,8 @@ The *warnings* argument specifies the :ref:`warning filter ` that should be used while running the tests. If it's not specified, it will - remain ``None`` if a :option:`-W` option is passed to :program:`python`, + remain ``None`` if a :option:`!-W` option is passed to :program:`python` + (see :ref:`Warning control `), otherwise it will be set to ``'default'``. Calling ``main`` actually returns an instance of the ``TestProgram`` class. diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -267,13 +267,13 @@ Warnings that are only of interest to the developer are ignored by default. As such you should make sure to test your code with typically ignored warnings made visible. You can do this from the command-line by passing :option:`-Wd <-W>` -to the interpreter (this is shorthand for :option:`-W default`). This enables +to the interpreter (this is shorthand for :option:`!-W default`). This enables default handling for all warnings, including those that are ignored by default. To change what action is taken for encountered warnings you simply change what -argument is passed to :option:`-W`, e.g. :option:`-W error`. See the +argument is passed to :option:`-W`, e.g. :option:`!-W error`. See the :option:`-W` flag for more details on what is possible. -To programmatically do the same as :option:`-Wd`, use:: +To programmatically do the same as :option:`!-Wd`, use:: warnings.simplefilter('default') diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -192,7 +192,7 @@ Issue a warning when comparing :class:`bytes` or :class:`bytearray` with :class:`str` or :class:`bytes` with :class:`int`. Issue an error when the - option is given twice (:option:`-bb`). + option is given twice (:option:`!-bb`). .. versionchanged:: 3.5 Affects comparisons of :class:`bytes` with :class:`int`. @@ -308,11 +308,12 @@ Print a message each time a module is initialized, showing the place (filename or built-in module) from which it is loaded. When given twice - (:option:`-vv`), print a message for each file that is checked for when + (:option:`!-vv`), print a message for each file that is checked for when searching for a module. Also provides information on module cleanup at exit. See also :envvar:`PYTHONVERBOSE`. +.. _using-on-warnings: .. cmdoption:: -W arg Warning control. Python's warning machinery by default prints warning diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -476,7 +476,7 @@ program creates and destroys objects. The detection of cycles can be disabled when Python is compiled, if you can't afford even a tiny speed penalty or suspect that the cycle collection is buggy, by specifying the -:option:`--without-cycle-gc` switch when running the :program:`configure` +:option:`!--without-cycle-gc` switch when running the :program:`configure` script. Several people tackled this problem and contributed to a solution. An early diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -692,7 +692,7 @@ faster than the system :func:`malloc` and have less memory overhead. The allocator uses C's :func:`malloc` function to get large pools of memory, and then fulfills smaller memory requests from these pools. It can be enabled by - providing the :option:`--with-pymalloc` option to the :program:`configure` + providing the :option:`!--with-pymalloc` option to the :program:`configure` script; see :file:`Objects/obmalloc.c` for the implementation details. Authors of C extension modules should test their code with the object allocator diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -758,7 +758,7 @@ operators. * Python 2.2 supports some command-line arguments for testing whether code will - work with the changed division semantics. Running python with :option:`-Q + work with the changed division semantics. Running python with :option:`!-Q warn` will cause a warning to be issued whenever division is applied to two integers. You can use this to find code that's affected by the change and fix it. By default, Python 2.2 will simply perform classic division without a @@ -779,8 +779,8 @@ Python's Unicode support has been enhanced a bit in 2.2. Unicode strings are usually stored as UCS-2, as 16-bit unsigned integers. Python 2.2 can also be compiled to use UCS-4, 32-bit unsigned integers, as its internal encoding by -supplying :option:`--enable-unicode=ucs4` to the configure script. (It's also -possible to specify :option:`--disable-unicode` to completely disable Unicode +supplying :option:`!--enable-unicode=ucs4` to the configure script. (It's also +possible to specify :option:`!--disable-unicode` to completely disable Unicode support.) When built to use UCS-4 (a "wide Python"), the interpreter can natively handle @@ -979,7 +979,7 @@ output have been corrected. (Contributed by Fred L. Drake, Jr. and Tim Peters.) * The :mod:`socket` module can be compiled to support IPv6; specify the - :option:`--enable-ipv6` option to Python's configure script. (Contributed by + :option:`!--enable-ipv6` option to Python's configure script. (Contributed by Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit @@ -1140,7 +1140,7 @@ in the main Python CVS tree, and many changes have been made to support MacOS X. The most significant change is the ability to build Python as a framework, - enabled by supplying the :option:`--enable-framework` option to the configure + enabled by supplying the :option:`!--enable-framework` option to the configure script when compiling Python. According to Jack Jansen, "This installs a self- contained Python installation plus the OS X framework "glue" into :file:`/Library/Frameworks/Python.framework` (or another location of choice). diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -394,7 +394,7 @@ line-endings. This feature can be disabled when compiling Python by specifying the -:option:`--without-universal-newlines` switch when running Python's +:option:`!--without-universal-newlines` switch when running Python's :program:`configure` script. @@ -1812,9 +1812,9 @@ In 2.1 and 2.2, pymalloc was an experimental feature and wasn't enabled by default; you had to explicitly enable it when compiling Python by providing the -:option:`--with-pymalloc` option to the :program:`configure` script. In 2.3, +:option:`!--with-pymalloc` option to the :program:`configure` script. In 2.3, pymalloc has had further enhancements and is now enabled by default; you'll have -to supply :option:`--without-pymalloc` to disable it. +to supply :option:`!--without-pymalloc` to disable it. This change is transparent to code written in Python; however, pymalloc may expose bugs in C extensions. Authors of C extension modules should test their @@ -1853,7 +1853,7 @@ features to catch memory overwrites and doubled frees in both extension modules and in the interpreter itself. To enable this support, compile a debugging version of the Python interpreter by running :program:`configure` with -:option:`--with-pydebug`. +:option:`!--with-pydebug`. To aid extension writers, a header file :file:`Misc/pymemcompat.h` is distributed with the source to Python 2.3 that allows Python extensions to use @@ -1879,11 +1879,11 @@ * The cycle detection implementation used by the garbage collection has proven to be stable, so it's now been made mandatory. You can no longer compile Python - without it, and the :option:`--with-cycle-gc` switch to :program:`configure` has + without it, and the :option:`!--with-cycle-gc` switch to :program:`configure` has been removed. * Python can now optionally be built as a shared library - (:file:`libpython2.3.so`) by supplying :option:`--enable-shared` when running + (:file:`libpython2.3.so`) by supplying :option:`!--enable-shared` when running Python's :program:`configure` script. (Contributed by Ondrej Palkovsky.) * The :c:macro:`DL_EXPORT` and :c:macro:`DL_IMPORT` macros are now deprecated. @@ -1892,7 +1892,7 @@ generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros. * The interpreter can be compiled without any docstrings for the built-in - functions and modules by supplying :option:`--without-doc-strings` to the + functions and modules by supplying :option:`!--without-doc-strings` to the :program:`configure` script. This makes the Python executable about 10% smaller, but will also mean that you can't get help for Python's built-ins. (Contributed by Gustavo Niemeyer.) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1483,10 +1483,10 @@ * Python can now be built with additional profiling for the interpreter itself, intended as an aid to people developing the Python core. Providing - :option:`--enable-profiling` to the :program:`configure` script will let you + :option:`!--enable-profiling` to the :program:`configure` script will let you profile the interpreter with :program:`gprof`, and providing the - :option:`--with-tsc` switch enables profiling using the Pentium's Time-Stamp- - Counter register. Note that the :option:`--with-tsc` switch is slightly + :option:`!--with-tsc` switch enables profiling using the Pentium's Time-Stamp- + Counter register. Note that the :option:`!--with-tsc` switch is slightly misnamed, because the profiling feature also works on the PowerPC platform, though that processor architecture doesn't call that register "the TSC register". (Contributed by Jeremy Hylton.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -236,7 +236,7 @@ Before a package can be uploaded, you must be able to build a distribution using the :command:`sdist` Distutils command. Once that works, you can run ``python setup.py upload`` to add your package to the PyPI archive. Optionally you can -GPG-sign the package by supplying the :option:`--sign` and :option:`--identity` +GPG-sign the package by supplying the :option:`!--sign` and :option:`!--identity` options. Package uploading was implemented by Martin von L?wis and Richard Jones. @@ -1639,7 +1639,7 @@ * The :mod:`webbrowser` module received a number of enhancements. It's now usable as a script with ``python -m webbrowser``, taking a URL as the argument; - there are a number of switches to control the behaviour (:option:`-n` for a new + there are a number of switches to control the behaviour (:option:`!-n` for a new browser window, :option:`!-t` for a new tab). New module-level functions, :func:`open_new` and :func:`open_new_tab`, were added to support this. The module's :func:`open` function supports an additional feature, an *autoraise* @@ -2209,7 +2209,7 @@ * MacOS X (10.3 and higher): dynamic loading of modules now uses the :c:func:`dlopen` function instead of MacOS-specific functions. -* MacOS X: an :option:`--enable-universalsdk` switch was added to the +* MacOS X: an :option:`!--enable-universalsdk` switch was added to the :program:`configure` script that compiles the interpreter as a universal binary able to run on both PowerPC and Intel processors. (Contributed by Ronald Oussoren; :issue:`2573`.) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -58,7 +58,7 @@ remaining compatible with existing code by not removing older features or syntax. When it's not possible to do that, Python 2.6 tries to do what it can, adding compatibility functions in a -:mod:`future_builtins` module and a :option:`-3` switch to warn about +:mod:`future_builtins` module and a :option:`!-3` switch to warn about usages that will become unsupported in 3.0. Some significant new packages have been added to the standard library, @@ -116,7 +116,7 @@ compatible with 3.0 can do ``from future_builtins import hex, map`` as necessary. -A new command-line switch, :option:`-3`, enables warnings +A new command-line switch, :option:`!-3`, enables warnings about features that will be removed in Python 3.0. You can run code with this switch to see how much work will be necessary to port code to 3.0. The value of this switch is available @@ -2992,7 +2992,7 @@ * On Mac OS X, Python 2.6 can be compiled as a 4-way universal build. The :program:`configure` script - can take a :option:`--with-universal-archs=[32-bit|64-bit|all]` + can take a :option:`!--with-universal-archs=[32-bit|64-bit|all]` switch, controlling whether the binaries are built for 32-bit architectures (x86, PowerPC), 64-bit (x86-64 and PPC-64), or both. (Contributed by Ronald Oussoren.) @@ -3147,7 +3147,7 @@ * When compiling a framework build of Python, you can now specify the framework name to be used by providing the - :option:`--with-framework-name=` option to the + :option:`!--with-framework-name=` option to the :program:`configure` script. * The :mod:`macfs` module has been removed. This in turn required the diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -198,8 +198,8 @@ * :func:`operator.isCallable` and :func:`operator.sequenceIncludes`, which are not supported in 3.x, now trigger warnings. -* The :option:`-3` switch now automatically - enables the :option:`-Qwarn <-Q>` switch that causes warnings +* The :option:`!-3` switch now automatically + enables the :option:`!-Qwarn` switch that causes warnings about using classic division with integers and long integers. @@ -390,7 +390,7 @@ args = parser.parse_args() print args.__dict__ -Unless you override it, :option:`-h` and :option:`--help` switches +Unless you override it, :option:`!-h` and :option:`!--help` switches are automatically added, and produce neatly formatted output:: -> ./python.exe argparse-example.py --help @@ -960,7 +960,7 @@ benchmark results on 32-bit machines have been mixed. Therefore, the default is to use base 2**30 on 64-bit machines and base 2**15 on 32-bit machines; on Unix, there's a new configure option - :option:`--enable-big-digits` that can be used to override this default. + :option:`!--enable-big-digits` that can be used to override this default. Apart from the performance improvements this change should be invisible to end users, with one exception: for testing and @@ -1844,12 +1844,12 @@ The :func:`~unittest.main` function supports some other new options: -* :option:`-b ` or :option:`--buffer` will buffer the standard output +* :option:`-b ` or :option:`!--buffer` will buffer the standard output and standard error streams during each test. If the test passes, any resulting output will be discarded; on failure, the buffered output will be displayed. -* :option:`-c ` or :option:`--catch` will cause the control-C interrupt +* :option:`-c ` or :option:`!--catch` will cause the control-C interrupt to be handled more gracefully. Instead of interrupting the test process immediately, the currently running test will be completed and then the partial results up to the interruption will be reported. @@ -1863,7 +1863,7 @@ :func:`~unittest.removeHandler` decorator that can be used to mark tests that should have the control-C handling disabled. -* :option:`-f ` or :option:`--failfast` makes +* :option:`-f ` or :option:`!--failfast` makes test execution stop immediately when a test fails instead of continuing to execute further tests. (Suggested by Cliff Dyer and implemented by Michael Foord; :issue:`8074`.) @@ -2238,19 +2238,19 @@ with ``Py``, or with ``_ctypes``. (Implemented by Thomas Heller; :issue:`3102`.) -* New configure option: the :option:`--with-system-expat` switch allows +* New configure option: the :option:`!--with-system-expat` switch allows building the :mod:`pyexpat` module to use the system Expat library. (Contributed by Arfrever Frehtes Taifersar Arahesis; :issue:`7609`.) * New configure option: the - :option:`--with-valgrind` option will now disable the pymalloc + :option:`!--with-valgrind` option will now disable the pymalloc allocator, which is difficult for the Valgrind memory-error detector to analyze correctly. Valgrind will therefore be better at detecting memory leaks and overruns. (Contributed by James Henstridge; :issue:`2422`.) * New configure option: you can now supply an empty string to - :option:`--with-dbmliborder=` in order to disable all of the various + :option:`!--with-dbmliborder=` in order to disable all of the various DBM modules. (Added by Arfrever Frehtes Taifersar Arahesis; :issue:`6491`.) @@ -2397,19 +2397,19 @@ renamed, moved, or is accessed through different paths. (Patch by Ziga Seilnacht and Jean-Paul Calderone; :issue:`1180193`.) -* The :file:`regrtest.py` script now takes a :option:`--randseed=` +* The :file:`regrtest.py` script now takes a :option:`!--randseed=` switch that takes an integer that will be used as the random seed - for the :option:`-r` option that executes tests in random order. - The :option:`-r` option also reports the seed that was used + for the :option:`!-r` option that executes tests in random order. + The :option:`!-r` option also reports the seed that was used (Added by Collin Winter.) -* Another :file:`regrtest.py` switch is :option:`-j`, which +* Another :file:`regrtest.py` switch is :option:`!-j`, which takes an integer specifying how many tests run in parallel. This allows reducing the total runtime on multi-core machines. This option is compatible with several other options, including the :option:`!-R` switch which is known to produce long runtimes. (Added by Antoine Pitrou, :issue:`6152`.) This can also be used - with a new :option:`-F` switch that runs selected tests in a loop + with a new :option:`!-F` switch that runs selected tests in a loop until they fail. (Added by Antoine Pitrou; :issue:`7312`.) * When executed as a script, the :file:`py_compile.py` module now diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -904,7 +904,7 @@ port from Python 2.x to Python 2.(x+1). Make sure all your tests pass. -2. (Still using 2.6:) Turn on the :option:`-3` command line switch. +2. (Still using 2.6:) Turn on the :option:`!-3` command line switch. This enables warnings about features that will be removed (or change) in 3.0. Run your test suite again, and fix code that you get warnings about until there are no warnings left, and all your -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:16 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI2NjM4?= =?utf-8?q?=3A_Cannot_directly_link_to_main_option_from_the_=E2=80=9Ctimei?= =?utf-8?b?dOKAnSBtb2R1bGU=?= Message-ID: <20161030055016.7773.87332.6D399788@psf.io> https://hg.python.org/cpython/rev/cf91d48aa353 changeset: 104816:cf91d48aa353 branch: 2.7 user: Martin Panter date: Sun Oct 30 05:41:04 2016 +0000 summary: Issue #26638: Cannot directly link to main option from the ?timeit? module This seems to be because the ?timeit? module defines its own set of options files: Doc/library/timeit.rst | 3 ++- Doc/using/cmdline.rst | 1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -232,7 +232,8 @@ The code here doesn't try to hide it, but you should be aware of it. The baseline overhead can be measured by invoking the program without arguments, and it might differ between Python versions. Also, to fairly compare older Python - versions to Python 2.3, you may want to use Python's :option:`-O` option for + versions to Python 2.3, you may want to use Python's :option:`!-O` + option (see :ref:`Optimizations `) for the older versions to avoid timing ``SET_LINENO`` instructions. diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -224,6 +224,7 @@ raises an exception. See also :envvar:`PYTHONINSPECT`. +.. _using-on-optimizations: .. cmdoption:: -O Turn on basic optimizations. This changes the filename extension for -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:16 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:16 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2326638=3A_Merge_option_warning_fixes_from_3=2E6?= Message-ID: <20161030055016.7102.79730.225BB4F6@psf.io> https://hg.python.org/cpython/rev/85e2cfe5b12d changeset: 104813:85e2cfe5b12d parent: 104809:73c29ae6564e parent: 104812:a0d272fbc7de user: Martin Panter date: Sun Oct 30 04:30:36 2016 +0000 summary: Issue #26638: Merge option warning fixes from 3.6 files: Doc/distutils/apiref.rst | 32 +++++++------- Doc/distutils/builtdist.rst | 32 +++++++------- Doc/distutils/configfile.rst | 6 +- Doc/distutils/extending.rst | 2 +- Doc/distutils/setupscript.rst | 2 +- Doc/distutils/sourcedist.rst | 12 ++-- Doc/extending/extending.rst | 2 +- Doc/install/index.rst | 50 +++++++++++----------- Doc/library/2to3.rst | 28 ++++++------ Doc/library/ctypes.rst | 4 +- Doc/library/gettext.rst | 2 +- Doc/library/unittest.rst | 6 +- Doc/library/warnings.rst | 6 +- Doc/using/cmdline.rst | 5 +- Doc/whatsnew/2.0.rst | 2 +- Doc/whatsnew/2.1.rst | 2 +- Doc/whatsnew/2.2.rst | 10 ++-- Doc/whatsnew/2.3.rst | 14 +++--- Doc/whatsnew/2.4.rst | 6 +- Doc/whatsnew/2.5.rst | 6 +- Doc/whatsnew/2.6.rst | 8 +- Doc/whatsnew/2.7.rst | 30 ++++++------ Doc/whatsnew/3.0.rst | 2 +- 23 files changed, 136 insertions(+), 133 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -205,7 +205,7 @@ | | to or ``None`` to define it | | | | without a particular value | | | | (equivalent of ``#define FOO`` | | - | | in source or :option:`-DFOO` | | + | | in source or :option:`!-DFOO` | | | | on Unix C compiler command | | | | line) | | +------------------------+--------------------------------+---------------------------+ @@ -319,11 +319,11 @@ .. function:: gen_preprocess_options(macros, include_dirs) - Generate C pre-processor options (:option:`-D`, :option:`!-U`, :option:`!-I`) as + Generate C pre-processor options (:option:`!-D`, :option:`!-U`, :option:`!-I`) as used by at least two types of compilers: the typical Unix compiler and Visual C++. *macros* is the usual thing, a list of 1- or 2-tuples, where ``(name,)`` means undefine (:option:`!-U`) macro *name*, and ``(name, value)`` means define - (:option:`-D`) macro *name* to *value*. *include_dirs* is just a list of + (:option:`!-D`) macro *name* to *value*. *include_dirs* is just a list of directory names to be added to the header file search path (:option:`!-I`). Returns a list of command-line options suitable for either Unix compilers or Visual C++. @@ -359,7 +359,7 @@ .. function:: show_compilers() - Print list of available compilers (used by the :option:`--help-compiler` options + Print list of available compilers (used by the :option:`!--help-compiler` options to :command:`build`, :command:`build_ext`, :command:`build_clib`). @@ -789,15 +789,15 @@ This module provides the :class:`UnixCCompiler` class, a subclass of :class:`CCompiler` that handles the typical Unix-style command-line C compiler: -* macros defined with :option:`-Dname[=value]` - -* macros undefined with :option:`-Uname` - -* include search directories specified with :option:`-Idir` - -* libraries specified with :option:`-llib` - -* library search directories specified with :option:`-Ldir` +* macros defined with :option:`!-Dname[=value]` + +* macros undefined with :option:`!-Uname` + +* include search directories specified with :option:`!-Idir` + +* libraries specified with :option:`!-llib` + +* library search directories specified with :option:`!-Ldir` * compile handled by :program:`cc` (or similar) executable with :option:`!-c` option: compiles :file:`.c` to :file:`.o` @@ -805,7 +805,7 @@ * link static library handled by :program:`ar` command (possibly with :program:`ranlib`) -* link shared library handled by :program:`cc` :option:`-shared` +* link shared library handled by :program:`cc` :option:`!-shared` :mod:`distutils.msvccompiler` --- Microsoft Compiler @@ -1318,8 +1318,8 @@ * options set attributes of a passed-in object -* boolean options can have "negative aliases" --- eg. if :option:`--quiet` is - the "negative alias" of :option:`--verbose`, then :option:`--quiet` on the +* boolean options can have "negative aliases" --- eg. if :option:`!--quiet` is + the "negative alias" of :option:`!--verbose`, then :option:`!--quiet` on the command line sets *verbose* to false. .. function:: fancy_getopt(options, negative_opt, object, args) diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -57,7 +57,7 @@ Windows, is far more convenient for users even if your distribution doesn't include any extensions. -The :command:`bdist` command has a :option:`--formats` option, similar to the +The :command:`bdist` command has a :option:`!--formats` option, similar to the :command:`sdist` command, which you can use to select the types of built distribution to generate: for example, :: @@ -123,7 +123,7 @@ requires external :program:`rpm` utility, version 3.0.4 or better (use ``rpm --version`` to find out which version you have) -You don't have to use the :command:`bdist` command with the :option:`--formats` +You don't have to use the :command:`bdist` command with the :option:`!--formats` option; you can also use the command that directly implements the format you're interested in. Some of these :command:`bdist` "sub-commands" actually generate several similar formats; for instance, the :command:`bdist_dumb` command @@ -174,7 +174,7 @@ python setup.py bdist_rpm -or the :command:`bdist` command with the :option:`--format` option:: +or the :command:`bdist` command with the :option:`!--format` option:: python setup.py bdist --formats=rpm @@ -249,7 +249,7 @@ you distribute or package many Python module distributions, you might want to put options that apply to all of them in your personal Distutils configuration file (:file:`~/.pydistutils.cfg`). If you want to temporarily disable -this file, you can pass the :option:`--no-user-cfg` option to :file:`setup.py`. +this file, you can pass the :option:`!--no-user-cfg` option to :file:`setup.py`. There are three steps to building a binary RPM package, all of which are handled automatically by the Distutils: @@ -267,10 +267,10 @@ all three steps are typically bundled together. If you wish, you can separate these three steps. You can use the -:option:`--spec-only` option to make :command:`bdist_rpm` just create the +:option:`!--spec-only` option to make :command:`bdist_rpm` just create the :file:`.spec` file and exit; in this case, the :file:`.spec` file will be written to the "distribution directory"---normally :file:`dist/`, but -customizable with the :option:`--dist-dir` option. (Normally, the :file:`.spec` +customizable with the :option:`!--dist-dir` option. (Normally, the :file:`.spec` file winds up deep in the "build tree," in a temporary directory created by :command:`bdist_rpm`.) @@ -307,7 +307,7 @@ python setup.py bdist_wininst -or the :command:`bdist` command with the :option:`--formats` option:: +or the :command:`bdist` command with the :option:`!--formats` option:: python setup.py bdist --formats=wininst @@ -325,20 +325,20 @@ The installer will try to compile pure modules into :term:`bytecode` after installation on the target system in normal and optimizing mode. If you don't want this to happen for some reason, you can run the :command:`bdist_wininst` command with -the :option:`--no-target-compile` and/or the :option:`--no-target-optimize` +the :option:`!--no-target-compile` and/or the :option:`!--no-target-optimize` option. By default the installer will display the cool "Python Powered" logo when it is run, but you can also supply your own 152x261 bitmap which must be a Windows -:file:`.bmp` file with the :option:`--bitmap` option. +:file:`.bmp` file with the :option:`!--bitmap` option. The installer will also display a large title on the desktop background window when it is run, which is constructed from the name of your distribution and the version number. This can be changed to another text by using the -:option:`--title` option. +:option:`!--title` option. The installer file will be written to the "distribution directory" --- normally -:file:`dist/`, but customizable with the :option:`--dist-dir` option. +:file:`dist/`, but customizable with the :option:`!--dist-dir` option. .. _cross-compile-windows: @@ -350,7 +350,7 @@ installed, you can use a 32bit version of Windows to create 64bit extensions and vice-versa. -To build for an alternate platform, specify the :option:`--plat-name` option +To build for an alternate platform, specify the :option:`!--plat-name` option to the build command. Valid values are currently 'win32', 'win-amd64' and 'win-ia64'. For example, on a 32bit version of Windows, you could execute:: @@ -383,14 +383,14 @@ --------------------------- Starting with Python 2.3, a postinstallation script can be specified with the -:option:`--install-script` option. The basename of the script must be +:option:`!--install-script` option. The basename of the script must be specified, and the script filename must also be listed in the scripts argument to the setup function. This script will be run at installation time on the target system after all the -files have been copied, with ``argv[1]`` set to :option:`-install`, and again at +files have been copied, with ``argv[1]`` set to :option:`!-install`, and again at uninstallation time before the files are removed with ``argv[1]`` set to -:option:`-remove`. +:option:`!-remove`. The installation script runs embedded in the windows installer, every output (``sys.stdout``, ``sys.stderr``) is redirected into a buffer and will be @@ -453,7 +453,7 @@ Vista User Access Control (UAC) =============================== -Starting with Python 2.6, bdist_wininst supports a :option:`--user-access-control` +Starting with Python 2.6, bdist_wininst supports a :option:`!--user-access-control` option. The default is 'none' (meaning no UAC handling is done), and other valid values are 'auto' (meaning prompt for UAC elevation if Python was installed for all users) and 'force' (meaning always prompt for elevation). diff --git a/Doc/distutils/configfile.rst b/Doc/distutils/configfile.rst --- a/Doc/distutils/configfile.rst +++ b/Doc/distutils/configfile.rst @@ -66,7 +66,7 @@ --swig-opts list of SWIG command line options [...] -Note that an option spelled :option:`--foo-bar` on the command-line is spelled +Note that an option spelled :option:`!--foo-bar` on the command-line is spelled ``foo_bar`` in configuration files. .. _distutils-build-ext-inplace: @@ -75,12 +75,12 @@ have an extension :mod:`pkg.ext`, and you want the compiled extension file (:file:`ext.so` on Unix, say) to be put in the same source directory as your pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`--inplace` option on the command-line to ensure this:: +:option:`!--inplace` option on the command-line to ensure this:: python setup.py build_ext --inplace But this requires that you always specify the :command:`build_ext` command -explicitly, and remember to provide :option:`--inplace`. An easier way is to +explicitly, and remember to provide :option:`!--inplace`. An easier way is to "set and forget" this option, by encoding it in :file:`setup.cfg`, the configuration file for this distribution:: diff --git a/Doc/distutils/extending.rst b/Doc/distutils/extending.rst --- a/Doc/distutils/extending.rst +++ b/Doc/distutils/extending.rst @@ -62,7 +62,7 @@ third-party extensions to provide support for additional packaging systems, but the commands can be used for anything distutils commands can be used for. A new configuration option, ``command_packages`` (command-line option -:option:`--command-packages`), can be used to specify additional packages to be +:option:`!--command-packages`), can be used to specify additional packages to be searched for modules implementing commands. Like all distutils options, this can be specified on the command line or in a configuration file. This option can only be set in the ``[global]`` section of a configuration file, or before diff --git a/Doc/distutils/setupscript.rst b/Doc/distutils/setupscript.rst --- a/Doc/distutils/setupscript.rst +++ b/Doc/distutils/setupscript.rst @@ -446,7 +446,7 @@ The only clever feature is that if the first line of the script starts with ``#!`` and contains the word "python", the Distutils will adjust the first line to refer to the current interpreter location. By default, it is replaced with -the current interpreter location. The :option:`--executable` (or :option:`-e`) +the current interpreter location. The :option:`!--executable` (or :option:`!-e`) option will allow the interpreter path to be explicitly overridden. The ``scripts`` option simply is a list of files to be handled in this diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -14,7 +14,7 @@ the current platform. The default format is a gzip'ed tar file (:file:`.tar.gz`) on Unix, and ZIP file on Windows. -You can specify as many formats as you like using the :option:`--formats` +You can specify as many formats as you like using the :option:`!--formats` option, for example:: python setup.py sdist --formats=gztar,zip @@ -147,7 +147,7 @@ :file:`examples/sample?/build`. All of this is done *after* the standard include set, so you can exclude files from the standard set with explicit instructions in the manifest template. (Or, you can use the -:option:`--no-defaults` option to disable the standard set entirely.) There are +:option:`!--no-defaults` option to disable the standard set entirely.) There are several other commands available in the manifest template mini-language; see section :ref:`sdist-cmd`. @@ -166,8 +166,8 @@ future reference, and then used to build the source distribution archive(s). You can disable the default set of included files with the -:option:`--no-defaults` option, and you can disable the standard exclude set -with :option:`--no-prune`. +:option:`!--no-defaults` option, and you can disable the standard exclude set +with :option:`!--no-prune`. Following the Distutils' own manifest template, let's trace how the :command:`sdist` command builds the list of files to include in the Distutils @@ -225,7 +225,7 @@ in) to create the source distribution archive(s) There are a couple of options that modify this behaviour. First, use the -:option:`--no-defaults` and :option:`--no-prune` to disable the standard +:option:`!--no-defaults` and :option:`!--no-prune` to disable the standard "include" and "exclude" sets. Second, you might just want to (re)generate the manifest, but not create a source @@ -233,4 +233,4 @@ python setup.py sdist --manifest-only -:option:`-o` is a shortcut for :option:`--manifest-only`. +:option:`!-o` is a shortcut for :option:`!--manifest-only`. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -886,7 +886,7 @@ :func:`~gc.collect` function), as well as configuration interfaces and the ability to disable the detector at runtime. The cycle detector is considered an optional component; though it is included by default, -it can be disabled at build time using the :option:`--without-cycle-gc` option +it can be disabled at build time using the :option:`!--without-cycle-gc` option to the :program:`configure` script on Unix platforms (including Mac OS X). If the cycle detector is disabled in this way, the :mod:`gc` module will not be available. diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -201,7 +201,7 @@ files to install into a *build directory*. By default, this is :file:`build` under the distribution root; if you're excessively concerned with speed, or want to keep the source tree pristine, you can change the build directory with the -:option:`--build-base` option. For example:: +:option:`!--build-base` option. For example:: python setup.py build --build-base=/path/to/pybuild/foo-1.0 @@ -399,7 +399,7 @@ python setup.py install --home= -where you can supply any directory you like for the :option:`--home` option. On +where you can supply any directory you like for the :option:`!--home` option. On Unix, lazy typists can just type a tilde (``~``); the :command:`install` command will expand this to your home directory:: @@ -410,7 +410,7 @@ :mod:`sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit :data:`sys.path`. -The :option:`--home` option defines the installation base directory. Files are +The :option:`!--home` option defines the installation base directory. Files are installed to the following directories under the installation base as follows: =============== =========================================================== @@ -455,12 +455,12 @@ /usr/local/bin/python setup.py install --prefix=/mnt/@server/export -In either case, the :option:`--prefix` option defines the installation base, and -the :option:`--exec-prefix` option defines the platform-specific installation +In either case, the :option:`!--prefix` option defines the installation base, and +the :option:`!--exec-prefix` option defines the platform-specific installation base, which is used for platform-specific files. (Currently, this just means non-pure module distributions, but could be expanded to C libraries, binary -executables, etc.) If :option:`--exec-prefix` is not supplied, it defaults to -:option:`--prefix`. Files are installed as follows: +executables, etc.) If :option:`!--exec-prefix` is not supplied, it defaults to +:option:`!--prefix`. Files are installed as follows: ================= ========================================================== Type of file Installation directory @@ -472,13 +472,13 @@ C headers :file:`{prefix}/include/python{X.Y}{abiflags}/{distname}` ================= ========================================================== -There is no requirement that :option:`--prefix` or :option:`--exec-prefix` +There is no requirement that :option:`!--prefix` or :option:`!--exec-prefix` actually point to an alternate Python installation; if the directories listed above do not already exist, they are created at installation time. Incidentally, the real reason the prefix scheme is important is simply that a -standard Unix installation uses the prefix scheme, but with :option:`--prefix` -and :option:`--exec-prefix` supplied by Python itself as ``sys.prefix`` and +standard Unix installation uses the prefix scheme, but with :option:`!--prefix` +and :option:`!--exec-prefix` supplied by Python itself as ``sys.prefix`` and ``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme, but every time you run ``python setup.py install`` without any other options, you're using it. @@ -491,7 +491,7 @@ in this way is compatible with the interpreter used to build them. The best way to do this is to ensure that the two interpreters are the same version of Python (possibly different builds, or possibly copies of the same build). (Of course, -if your :option:`--prefix` and :option:`--exec-prefix` don't even point to an +if your :option:`!--prefix` and :option:`!--exec-prefix` don't even point to an alternate Python installation, this is immaterial.) @@ -501,7 +501,7 @@ --------------------------------------------------- Windows has no concept of a user's home directory, and since the standard Python -installation under Windows is simpler than under Unix, the :option:`--prefix` +installation under Windows is simpler than under Unix, the :option:`!--prefix` option has traditionally been used to install additional packages in separate locations on Windows. :: @@ -509,8 +509,8 @@ to install modules to the :file:`\\Temp\\Python` directory on the current drive. -The installation base is defined by the :option:`--prefix` option; the -:option:`--exec-prefix` option is not supported under Windows, which means that +The installation base is defined by the :option:`!--prefix` option; the +:option:`!--exec-prefix` option is not supported under Windows, which means that pure Python modules and extension modules are installed into the same location. Files are installed as follows: @@ -562,7 +562,7 @@ For example, say you're installing a module distribution to your home directory under Unix---but you want scripts to go in :file:`~/scripts` rather than :file:`~/bin`. As you might expect, you can override this directory with the -:option:`--install-scripts` option; in this case, it makes most sense to supply +:option:`!--install-scripts` option; in this case, it makes most sense to supply a relative path, which will be interpreted relative to the installation base directory (your home directory, in this case):: @@ -572,7 +572,7 @@ with a prefix of :file:`/usr/local/python`, so under a standard installation scripts will wind up in :file:`/usr/local/python/bin`. If you want them in :file:`/usr/local/bin` instead, you would supply this absolute directory for the -:option:`--install-scripts` option:: +:option:`!--install-scripts` option:: python setup.py install --install-scripts=/usr/local/bin @@ -932,10 +932,10 @@ to be in Objective C. * *cpparg* is an argument for the C preprocessor, and is anything starting with - :option:`!-I`, :option:`-D`, :option:`!-U` or :option:`-C`. + :option:`!-I`, :option:`!-D`, :option:`!-U` or :option:`!-C`. -* *library* is anything ending in :file:`.a` or beginning with :option:`-l` or - :option:`-L`. +* *library* is anything ending in :file:`.a` or beginning with :option:`!-l` or + :option:`!-L`. If a particular platform requires a special library on your platform, you can add it by editing the :file:`Setup` file and running ``python setup.py build``. @@ -944,20 +944,20 @@ foo foomodule.c must be linked with the math library :file:`libm.a` on your platform, simply add -:option:`-lm` to the line:: +:option:`!-lm` to the line:: foo foomodule.c -lm Arbitrary switches intended for the compiler or the linker can be supplied with -the :option:`-Xcompiler` *arg* and :option:`-Xlinker` *arg* options:: +the :option:`!-Xcompiler` *arg* and :option:`!-Xlinker` *arg* options:: foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm -The next option after :option:`-Xcompiler` and :option:`-Xlinker` will be +The next option after :option:`!-Xcompiler` and :option:`!-Xlinker` will be appended to the proper command line, so in the above example the compiler will -be passed the :option:`-o32` option, and the linker will be passed -:option:`-shared`. If a compiler option requires an argument, you'll have to -supply multiple :option:`-Xcompiler` options; for example, to pass ``-x c++`` +be passed the :option:`!-o32` option, and the linker will be passed +:option:`!-shared`. If a compiler option requires an argument, you'll have to +supply multiple :option:`!-Xcompiler` options; for example, to pass ``-x c++`` the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``. Compiler flags can also be supplied through setting the :envvar:`CFLAGS` diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst --- a/Doc/library/2to3.rst +++ b/Doc/library/2to3.rst @@ -41,8 +41,8 @@ A diff against the original source file is printed. 2to3 can also write the needed modifications right back to the source file. (A backup of the original -file is made unless :option:`-n` is also given.) Writing the changes back is -enabled with the :option:`-w` flag: +file is made unless :option:`!-n` is also given.) Writing the changes back is +enabled with the :option:`!-w` flag: .. code-block:: shell-session @@ -60,7 +60,7 @@ By default, 2to3 runs a set of :ref:`predefined fixers <2to3-fixers>`. The :option:`!-l` flag lists all available fixers. An explicit set of fixers to run -can be given with :option:`-f`. Likewise the :option:`!-x` explicitly disables a +can be given with :option:`!-f`. Likewise the :option:`!-x` explicitly disables a fixer. The following example runs only the ``imports`` and ``has_key`` fixers: .. code-block:: shell-session @@ -100,29 +100,29 @@ cannot always read files containing the print function. When 2to3 detects the presence of the ``from __future__ import print_function`` compiler directive, it modifies its internal grammar to interpret :func:`print` as a function. This -change can also be enabled manually with the :option:`-p` flag. Use -:option:`-p` to run fixers on code that already has had its print statements +change can also be enabled manually with the :option:`!-p` flag. Use +:option:`!-p` to run fixers on code that already has had its print statements converted. -The :option:`-o` or :option:`--output-dir` option allows specification of an +The :option:`!-o` or :option:`!--output-dir` option allows specification of an alternate directory for processed output files to be written to. The -:option:`-n` flag is required when using this as backup files do not make sense +:option:`!-n` flag is required when using this as backup files do not make sense when not overwriting the input files. .. versionadded:: 3.2.3 - The :option:`-o` option was added. + The :option:`!-o` option was added. -The :option:`!-W` or :option:`--write-unchanged-files` flag tells 2to3 to always +The :option:`!-W` or :option:`!--write-unchanged-files` flag tells 2to3 to always write output files even if no changes were required to the file. This is most -useful with :option:`-o` so that an entire Python source tree is copied with +useful with :option:`!-o` so that an entire Python source tree is copied with translation from one directory to another. -This option implies the :option:`-w` flag as it would not make sense otherwise. +This option implies the :option:`!-w` flag as it would not make sense otherwise. .. versionadded:: 3.2.3 The :option:`!-W` flag was added. -The :option:`--add-suffix` option specifies a string to append to all output -filenames. The :option:`-n` flag is required when specifying this as backups +The :option:`!--add-suffix` option specifies a string to append to all output +filenames. The :option:`!-n` flag is required when specifying this as backups are not necessary when writing to different filenames. Example: .. code-block:: shell-session @@ -132,7 +132,7 @@ Will cause a converted file named ``example.py3`` to be written. .. versionadded:: 3.2.3 - The :option:`--add-suffix` option was added. + The :option:`!--add-suffix` option was added. To translate an entire project from one directory tree to another use: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1254,7 +1254,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like *lib*, suffix like ``.so``, ``.dylib`` or version number (this - is the form used for the posix linker option :option:`-l`). If no library can + is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. @@ -1838,7 +1838,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like ``lib``, suffix like ``.so``, ``.dylib`` or version - number (this is the form used for the posix linker option :option:`-l`). If + number (this is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -621,7 +621,7 @@ However, you will need to teach your message extraction program to look for translatable strings marked with :func:`N_`. :program:`xgettext`, :program:`pygettext`, ``pybabel extract``, and :program:`xpot` all -support this through the use of the :option:`-k` command-line switch. +support this through the use of the :option:`!-k` command-line switch. The choice of :func:`N_` here is totally arbitrary; it could have just as easily been :func:`MarkThisStringForTranslation`. diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1972,7 +1972,8 @@ methods ` are also special-cased and, when the warning filters are ``'default'`` or ``'always'``, they will appear only once per-module, in order to avoid too many warning messages. This behavior can - be overridden using the :option:`-Wd` or :option:`-Wa` options and leaving + be overridden using Python's :option:`!-Wd` or :option:`!-Wa` options + (see :ref:`Warning control `) and leaving *warnings* to ``None``. .. versionchanged:: 3.2 @@ -2053,7 +2054,8 @@ The *warnings* argument specifies the :ref:`warning filter ` that should be used while running the tests. If it's not specified, it will - remain ``None`` if a :option:`-W` option is passed to :program:`python`, + remain ``None`` if a :option:`!-W` option is passed to :program:`python` + (see :ref:`Warning control `), otherwise it will be set to ``'default'``. Calling ``main`` actually returns an instance of the ``TestProgram`` class. diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -267,13 +267,13 @@ Warnings that are only of interest to the developer are ignored by default. As such you should make sure to test your code with typically ignored warnings made visible. You can do this from the command-line by passing :option:`-Wd <-W>` -to the interpreter (this is shorthand for :option:`-W default`). This enables +to the interpreter (this is shorthand for :option:`!-W default`). This enables default handling for all warnings, including those that are ignored by default. To change what action is taken for encountered warnings you simply change what -argument is passed to :option:`-W`, e.g. :option:`-W error`. See the +argument is passed to :option:`-W`, e.g. :option:`!-W error`. See the :option:`-W` flag for more details on what is possible. -To programmatically do the same as :option:`-Wd`, use:: +To programmatically do the same as :option:`!-Wd`, use:: warnings.simplefilter('default') diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -192,7 +192,7 @@ Issue a warning when comparing :class:`bytes` or :class:`bytearray` with :class:`str` or :class:`bytes` with :class:`int`. Issue an error when the - option is given twice (:option:`-bb`). + option is given twice (:option:`!-bb`). .. versionchanged:: 3.5 Affects comparisons of :class:`bytes` with :class:`int`. @@ -308,11 +308,12 @@ Print a message each time a module is initialized, showing the place (filename or built-in module) from which it is loaded. When given twice - (:option:`-vv`), print a message for each file that is checked for when + (:option:`!-vv`), print a message for each file that is checked for when searching for a module. Also provides information on module cleanup at exit. See also :envvar:`PYTHONVERBOSE`. +.. _using-on-warnings: .. cmdoption:: -W arg Warning control. Python's warning machinery by default prints warning diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -476,7 +476,7 @@ program creates and destroys objects. The detection of cycles can be disabled when Python is compiled, if you can't afford even a tiny speed penalty or suspect that the cycle collection is buggy, by specifying the -:option:`--without-cycle-gc` switch when running the :program:`configure` +:option:`!--without-cycle-gc` switch when running the :program:`configure` script. Several people tackled this problem and contributed to a solution. An early diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -692,7 +692,7 @@ faster than the system :func:`malloc` and have less memory overhead. The allocator uses C's :func:`malloc` function to get large pools of memory, and then fulfills smaller memory requests from these pools. It can be enabled by - providing the :option:`--with-pymalloc` option to the :program:`configure` + providing the :option:`!--with-pymalloc` option to the :program:`configure` script; see :file:`Objects/obmalloc.c` for the implementation details. Authors of C extension modules should test their code with the object allocator diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -758,7 +758,7 @@ operators. * Python 2.2 supports some command-line arguments for testing whether code will - work with the changed division semantics. Running python with :option:`-Q + work with the changed division semantics. Running python with :option:`!-Q warn` will cause a warning to be issued whenever division is applied to two integers. You can use this to find code that's affected by the change and fix it. By default, Python 2.2 will simply perform classic division without a @@ -779,8 +779,8 @@ Python's Unicode support has been enhanced a bit in 2.2. Unicode strings are usually stored as UCS-2, as 16-bit unsigned integers. Python 2.2 can also be compiled to use UCS-4, 32-bit unsigned integers, as its internal encoding by -supplying :option:`--enable-unicode=ucs4` to the configure script. (It's also -possible to specify :option:`--disable-unicode` to completely disable Unicode +supplying :option:`!--enable-unicode=ucs4` to the configure script. (It's also +possible to specify :option:`!--disable-unicode` to completely disable Unicode support.) When built to use UCS-4 (a "wide Python"), the interpreter can natively handle @@ -979,7 +979,7 @@ output have been corrected. (Contributed by Fred L. Drake, Jr. and Tim Peters.) * The :mod:`socket` module can be compiled to support IPv6; specify the - :option:`--enable-ipv6` option to Python's configure script. (Contributed by + :option:`!--enable-ipv6` option to Python's configure script. (Contributed by Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit @@ -1140,7 +1140,7 @@ in the main Python CVS tree, and many changes have been made to support MacOS X. The most significant change is the ability to build Python as a framework, - enabled by supplying the :option:`--enable-framework` option to the configure + enabled by supplying the :option:`!--enable-framework` option to the configure script when compiling Python. According to Jack Jansen, "This installs a self- contained Python installation plus the OS X framework "glue" into :file:`/Library/Frameworks/Python.framework` (or another location of choice). diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -394,7 +394,7 @@ line-endings. This feature can be disabled when compiling Python by specifying the -:option:`--without-universal-newlines` switch when running Python's +:option:`!--without-universal-newlines` switch when running Python's :program:`configure` script. @@ -1812,9 +1812,9 @@ In 2.1 and 2.2, pymalloc was an experimental feature and wasn't enabled by default; you had to explicitly enable it when compiling Python by providing the -:option:`--with-pymalloc` option to the :program:`configure` script. In 2.3, +:option:`!--with-pymalloc` option to the :program:`configure` script. In 2.3, pymalloc has had further enhancements and is now enabled by default; you'll have -to supply :option:`--without-pymalloc` to disable it. +to supply :option:`!--without-pymalloc` to disable it. This change is transparent to code written in Python; however, pymalloc may expose bugs in C extensions. Authors of C extension modules should test their @@ -1853,7 +1853,7 @@ features to catch memory overwrites and doubled frees in both extension modules and in the interpreter itself. To enable this support, compile a debugging version of the Python interpreter by running :program:`configure` with -:option:`--with-pydebug`. +:option:`!--with-pydebug`. To aid extension writers, a header file :file:`Misc/pymemcompat.h` is distributed with the source to Python 2.3 that allows Python extensions to use @@ -1879,11 +1879,11 @@ * The cycle detection implementation used by the garbage collection has proven to be stable, so it's now been made mandatory. You can no longer compile Python - without it, and the :option:`--with-cycle-gc` switch to :program:`configure` has + without it, and the :option:`!--with-cycle-gc` switch to :program:`configure` has been removed. * Python can now optionally be built as a shared library - (:file:`libpython2.3.so`) by supplying :option:`--enable-shared` when running + (:file:`libpython2.3.so`) by supplying :option:`!--enable-shared` when running Python's :program:`configure` script. (Contributed by Ondrej Palkovsky.) * The :c:macro:`DL_EXPORT` and :c:macro:`DL_IMPORT` macros are now deprecated. @@ -1892,7 +1892,7 @@ generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros. * The interpreter can be compiled without any docstrings for the built-in - functions and modules by supplying :option:`--without-doc-strings` to the + functions and modules by supplying :option:`!--without-doc-strings` to the :program:`configure` script. This makes the Python executable about 10% smaller, but will also mean that you can't get help for Python's built-ins. (Contributed by Gustavo Niemeyer.) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1483,10 +1483,10 @@ * Python can now be built with additional profiling for the interpreter itself, intended as an aid to people developing the Python core. Providing - :option:`--enable-profiling` to the :program:`configure` script will let you + :option:`!--enable-profiling` to the :program:`configure` script will let you profile the interpreter with :program:`gprof`, and providing the - :option:`--with-tsc` switch enables profiling using the Pentium's Time-Stamp- - Counter register. Note that the :option:`--with-tsc` switch is slightly + :option:`!--with-tsc` switch enables profiling using the Pentium's Time-Stamp- + Counter register. Note that the :option:`!--with-tsc` switch is slightly misnamed, because the profiling feature also works on the PowerPC platform, though that processor architecture doesn't call that register "the TSC register". (Contributed by Jeremy Hylton.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -236,7 +236,7 @@ Before a package can be uploaded, you must be able to build a distribution using the :command:`sdist` Distutils command. Once that works, you can run ``python setup.py upload`` to add your package to the PyPI archive. Optionally you can -GPG-sign the package by supplying the :option:`--sign` and :option:`--identity` +GPG-sign the package by supplying the :option:`!--sign` and :option:`!--identity` options. Package uploading was implemented by Martin von L?wis and Richard Jones. @@ -1639,7 +1639,7 @@ * The :mod:`webbrowser` module received a number of enhancements. It's now usable as a script with ``python -m webbrowser``, taking a URL as the argument; - there are a number of switches to control the behaviour (:option:`-n` for a new + there are a number of switches to control the behaviour (:option:`!-n` for a new browser window, :option:`!-t` for a new tab). New module-level functions, :func:`open_new` and :func:`open_new_tab`, were added to support this. The module's :func:`open` function supports an additional feature, an *autoraise* @@ -2209,7 +2209,7 @@ * MacOS X (10.3 and higher): dynamic loading of modules now uses the :c:func:`dlopen` function instead of MacOS-specific functions. -* MacOS X: an :option:`--enable-universalsdk` switch was added to the +* MacOS X: an :option:`!--enable-universalsdk` switch was added to the :program:`configure` script that compiles the interpreter as a universal binary able to run on both PowerPC and Intel processors. (Contributed by Ronald Oussoren; :issue:`2573`.) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -58,7 +58,7 @@ remaining compatible with existing code by not removing older features or syntax. When it's not possible to do that, Python 2.6 tries to do what it can, adding compatibility functions in a -:mod:`future_builtins` module and a :option:`-3` switch to warn about +:mod:`future_builtins` module and a :option:`!-3` switch to warn about usages that will become unsupported in 3.0. Some significant new packages have been added to the standard library, @@ -116,7 +116,7 @@ compatible with 3.0 can do ``from future_builtins import hex, map`` as necessary. -A new command-line switch, :option:`-3`, enables warnings +A new command-line switch, :option:`!-3`, enables warnings about features that will be removed in Python 3.0. You can run code with this switch to see how much work will be necessary to port code to 3.0. The value of this switch is available @@ -2992,7 +2992,7 @@ * On Mac OS X, Python 2.6 can be compiled as a 4-way universal build. The :program:`configure` script - can take a :option:`--with-universal-archs=[32-bit|64-bit|all]` + can take a :option:`!--with-universal-archs=[32-bit|64-bit|all]` switch, controlling whether the binaries are built for 32-bit architectures (x86, PowerPC), 64-bit (x86-64 and PPC-64), or both. (Contributed by Ronald Oussoren.) @@ -3147,7 +3147,7 @@ * When compiling a framework build of Python, you can now specify the framework name to be used by providing the - :option:`--with-framework-name=` option to the + :option:`!--with-framework-name=` option to the :program:`configure` script. * The :mod:`macfs` module has been removed. This in turn required the diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -198,8 +198,8 @@ * :func:`operator.isCallable` and :func:`operator.sequenceIncludes`, which are not supported in 3.x, now trigger warnings. -* The :option:`-3` switch now automatically - enables the :option:`-Qwarn <-Q>` switch that causes warnings +* The :option:`!-3` switch now automatically + enables the :option:`!-Qwarn` switch that causes warnings about using classic division with integers and long integers. @@ -390,7 +390,7 @@ args = parser.parse_args() print args.__dict__ -Unless you override it, :option:`-h` and :option:`--help` switches +Unless you override it, :option:`!-h` and :option:`!--help` switches are automatically added, and produce neatly formatted output:: -> ./python.exe argparse-example.py --help @@ -960,7 +960,7 @@ benchmark results on 32-bit machines have been mixed. Therefore, the default is to use base 2**30 on 64-bit machines and base 2**15 on 32-bit machines; on Unix, there's a new configure option - :option:`--enable-big-digits` that can be used to override this default. + :option:`!--enable-big-digits` that can be used to override this default. Apart from the performance improvements this change should be invisible to end users, with one exception: for testing and @@ -1844,12 +1844,12 @@ The :func:`~unittest.main` function supports some other new options: -* :option:`-b ` or :option:`--buffer` will buffer the standard output +* :option:`-b ` or :option:`!--buffer` will buffer the standard output and standard error streams during each test. If the test passes, any resulting output will be discarded; on failure, the buffered output will be displayed. -* :option:`-c ` or :option:`--catch` will cause the control-C interrupt +* :option:`-c ` or :option:`!--catch` will cause the control-C interrupt to be handled more gracefully. Instead of interrupting the test process immediately, the currently running test will be completed and then the partial results up to the interruption will be reported. @@ -1863,7 +1863,7 @@ :func:`~unittest.removeHandler` decorator that can be used to mark tests that should have the control-C handling disabled. -* :option:`-f ` or :option:`--failfast` makes +* :option:`-f ` or :option:`!--failfast` makes test execution stop immediately when a test fails instead of continuing to execute further tests. (Suggested by Cliff Dyer and implemented by Michael Foord; :issue:`8074`.) @@ -2238,19 +2238,19 @@ with ``Py``, or with ``_ctypes``. (Implemented by Thomas Heller; :issue:`3102`.) -* New configure option: the :option:`--with-system-expat` switch allows +* New configure option: the :option:`!--with-system-expat` switch allows building the :mod:`pyexpat` module to use the system Expat library. (Contributed by Arfrever Frehtes Taifersar Arahesis; :issue:`7609`.) * New configure option: the - :option:`--with-valgrind` option will now disable the pymalloc + :option:`!--with-valgrind` option will now disable the pymalloc allocator, which is difficult for the Valgrind memory-error detector to analyze correctly. Valgrind will therefore be better at detecting memory leaks and overruns. (Contributed by James Henstridge; :issue:`2422`.) * New configure option: you can now supply an empty string to - :option:`--with-dbmliborder=` in order to disable all of the various + :option:`!--with-dbmliborder=` in order to disable all of the various DBM modules. (Added by Arfrever Frehtes Taifersar Arahesis; :issue:`6491`.) @@ -2397,19 +2397,19 @@ renamed, moved, or is accessed through different paths. (Patch by Ziga Seilnacht and Jean-Paul Calderone; :issue:`1180193`.) -* The :file:`regrtest.py` script now takes a :option:`--randseed=` +* The :file:`regrtest.py` script now takes a :option:`!--randseed=` switch that takes an integer that will be used as the random seed - for the :option:`-r` option that executes tests in random order. - The :option:`-r` option also reports the seed that was used + for the :option:`!-r` option that executes tests in random order. + The :option:`!-r` option also reports the seed that was used (Added by Collin Winter.) -* Another :file:`regrtest.py` switch is :option:`-j`, which +* Another :file:`regrtest.py` switch is :option:`!-j`, which takes an integer specifying how many tests run in parallel. This allows reducing the total runtime on multi-core machines. This option is compatible with several other options, including the :option:`!-R` switch which is known to produce long runtimes. (Added by Antoine Pitrou, :issue:`6152`.) This can also be used - with a new :option:`-F` switch that runs selected tests in a loop + with a new :option:`!-F` switch that runs selected tests in a loop until they fail. (Added by Antoine Pitrou; :issue:`7312`.) * When executed as a script, the :file:`py_compile.py` module now diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -904,7 +904,7 @@ port from Python 2.x to Python 2.(x+1). Make sure all your tests pass. -2. (Still using 2.6:) Turn on the :option:`-3` command line switch. +2. (Still using 2.6:) Turn on the :option:`!-3` command line switch. This enables warnings about features that will be removed (or change) in 3.0. Run your test suite again, and fix code that you get warnings about until there are no warnings left, and all your -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 01:50:16 2016 From: python-checkins at python.org (martin.panter) Date: Sun, 30 Oct 2016 05:50:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI2NjM4?= =?utf-8?q?=3A_Mask_undefined_CLI_options_to_defeat_new_Sphinx_warnings?= Message-ID: <20161030055016.45195.51661.10FBCDF1@psf.io> https://hg.python.org/cpython/rev/0ff00d53d6a9 changeset: 104815:0ff00d53d6a9 branch: 2.7 user: Martin Panter date: Sun Oct 30 05:19:02 2016 +0000 summary: Issue #26638: Mask undefined CLI options to defeat new Sphinx warnings files: Doc/distutils/apiref.rst | 32 +++++++------- Doc/distutils/builtdist.rst | 30 ++++++------ Doc/distutils/configfile.rst | 6 +- Doc/distutils/extending.rst | 2 +- Doc/distutils/setupscript.rst | 2 +- Doc/distutils/sourcedist.rst | 12 ++-- Doc/extending/extending.rst | 2 +- Doc/install/index.rst | 52 +++++++++++----------- Doc/library/2to3.rst | 30 ++++++------ Doc/library/ctypes.rst | 4 +- Doc/library/easydialogs.rst | 4 +- Doc/library/warnings.rst | 6 +- Doc/using/cmdline.rst | 6 +- Doc/whatsnew/2.0.rst | 2 +- Doc/whatsnew/2.1.rst | 2 +- Doc/whatsnew/2.2.rst | 8 +- Doc/whatsnew/2.3.rst | 14 +++--- Doc/whatsnew/2.4.rst | 6 +- Doc/whatsnew/2.5.rst | 6 +- Doc/whatsnew/2.6.rst | 4 +- Doc/whatsnew/2.7.rst | 26 +++++----- 21 files changed, 128 insertions(+), 128 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -205,7 +205,7 @@ | | to or ``None`` to define it | | | | without a particular value | | | | (equivalent of ``#define FOO`` | | - | | in source or :option:`-DFOO` | | + | | in source or :option:`!-DFOO` | | | | on Unix C compiler command | | | | line) | | +------------------------+--------------------------------+---------------------------+ @@ -314,11 +314,11 @@ .. function:: gen_preprocess_options(macros, include_dirs) - Generate C pre-processor options (:option:`-D`, :option:`!-U`, :option:`!-I`) as + Generate C pre-processor options (:option:`!-D`, :option:`!-U`, :option:`!-I`) as used by at least two types of compilers: the typical Unix compiler and Visual C++. *macros* is the usual thing, a list of 1- or 2-tuples, where ``(name,)`` means undefine (:option:`!-U`) macro *name*, and ``(name, value)`` means define - (:option:`-D`) macro *name* to *value*. *include_dirs* is just a list of + (:option:`!-D`) macro *name* to *value*. *include_dirs* is just a list of directory names to be added to the header file search path (:option:`!-I`). Returns a list of command-line options suitable for either Unix compilers or Visual C++. @@ -354,7 +354,7 @@ .. function:: show_compilers() - Print list of available compilers (used by the :option:`--help-compiler` options + Print list of available compilers (used by the :option:`!--help-compiler` options to :command:`build`, :command:`build_ext`, :command:`build_clib`). @@ -784,15 +784,15 @@ This module provides the :class:`UnixCCompiler` class, a subclass of :class:`CCompiler` that handles the typical Unix-style command-line C compiler: -* macros defined with :option:`-Dname[=value]` - -* macros undefined with :option:`-Uname` - -* include search directories specified with :option:`-Idir` - -* libraries specified with :option:`-llib` - -* library search directories specified with :option:`-Ldir` +* macros defined with :option:`!-Dname[=value]` + +* macros undefined with :option:`!-Uname` + +* include search directories specified with :option:`!-Idir` + +* libraries specified with :option:`!-llib` + +* library search directories specified with :option:`!-Ldir` * compile handled by :program:`cc` (or similar) executable with :option:`!-c` option: compiles :file:`.c` to :file:`.o` @@ -800,7 +800,7 @@ * link static library handled by :program:`ar` command (possibly with :program:`ranlib`) -* link shared library handled by :program:`cc` :option:`-shared` +* link shared library handled by :program:`cc` :option:`!-shared` :mod:`distutils.msvccompiler` --- Microsoft Compiler @@ -1310,8 +1310,8 @@ * options set attributes of a passed-in object -* boolean options can have "negative aliases" --- eg. if :option:`--quiet` is - the "negative alias" of :option:`--verbose`, then :option:`--quiet` on the +* boolean options can have "negative aliases" --- eg. if :option:`!--quiet` is + the "negative alias" of :option:`!--verbose`, then :option:`!--quiet` on the command line sets *verbose* to false. diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst --- a/Doc/distutils/builtdist.rst +++ b/Doc/distutils/builtdist.rst @@ -57,7 +57,7 @@ Windows, is far more convenient for users even if your distribution doesn't include any extensions. -The :command:`bdist` command has a :option:`--formats` option, similar to the +The :command:`bdist` command has a :option:`!--formats` option, similar to the :command:`sdist` command, which you can use to select the types of built distribution to generate: for example, :: @@ -115,7 +115,7 @@ requires external :program:`rpm` utility, version 3.0.4 or better (use ``rpm --version`` to find out which version you have) -You don't have to use the :command:`bdist` command with the :option:`--formats` +You don't have to use the :command:`bdist` command with the :option:`!--formats` option; you can also use the command that directly implements the format you're interested in. Some of these :command:`bdist` "sub-commands" actually generate several similar formats; for instance, the :command:`bdist_dumb` command @@ -165,7 +165,7 @@ python setup.py bdist_rpm -or the :command:`bdist` command with the :option:`--format` option:: +or the :command:`bdist` command with the :option:`!--format` option:: python setup.py bdist --formats=rpm @@ -258,10 +258,10 @@ all three steps are typically bundled together. If you wish, you can separate these three steps. You can use the -:option:`--spec-only` option to make :command:`bdist_rpm` just create the +:option:`!--spec-only` option to make :command:`bdist_rpm` just create the :file:`.spec` file and exit; in this case, the :file:`.spec` file will be written to the "distribution directory"---normally :file:`dist/`, but -customizable with the :option:`--dist-dir` option. (Normally, the :file:`.spec` +customizable with the :option:`!--dist-dir` option. (Normally, the :file:`.spec` file winds up deep in the "build tree," in a temporary directory created by :command:`bdist_rpm`.) @@ -298,7 +298,7 @@ python setup.py bdist_wininst -or the :command:`bdist` command with the :option:`--formats` option:: +or the :command:`bdist` command with the :option:`!--formats` option:: python setup.py bdist --formats=wininst @@ -316,20 +316,20 @@ The installer will try to compile pure modules into :term:`bytecode` after installation on the target system in normal and optimizing mode. If you don't want this to happen for some reason, you can run the :command:`bdist_wininst` command with -the :option:`--no-target-compile` and/or the :option:`--no-target-optimize` +the :option:`!--no-target-compile` and/or the :option:`!--no-target-optimize` option. By default the installer will display the cool "Python Powered" logo when it is run, but you can also supply your own 152x261 bitmap which must be a Windows -:file:`.bmp` file with the :option:`--bitmap` option. +:file:`.bmp` file with the :option:`!--bitmap` option. The installer will also display a large title on the desktop background window when it is run, which is constructed from the name of your distribution and the version number. This can be changed to another text by using the -:option:`--title` option. +:option:`!--title` option. The installer file will be written to the "distribution directory" --- normally -:file:`dist/`, but customizable with the :option:`--dist-dir` option. +:file:`dist/`, but customizable with the :option:`!--dist-dir` option. .. _cross-compile-windows: @@ -341,7 +341,7 @@ installed, you can use a 32bit version of Windows to create 64bit extensions and vice-versa. -To build for an alternate platform, specify the :option:`--plat-name` option +To build for an alternate platform, specify the :option:`!--plat-name` option to the build command. Valid values are currently 'win32', 'win-amd64' and 'win-ia64'. For example, on a 32bit version of Windows, you could execute:: @@ -374,14 +374,14 @@ --------------------------- Starting with Python 2.3, a postinstallation script can be specified with the -:option:`--install-script` option. The basename of the script must be +:option:`!--install-script` option. The basename of the script must be specified, and the script filename must also be listed in the scripts argument to the setup function. This script will be run at installation time on the target system after all the -files have been copied, with ``argv[1]`` set to :option:`-install`, and again at +files have been copied, with ``argv[1]`` set to :option:`!-install`, and again at uninstallation time before the files are removed with ``argv[1]`` set to -:option:`-remove`. +:option:`!-remove`. The installation script runs embedded in the windows installer, every output (``sys.stdout``, ``sys.stderr``) is redirected into a buffer and will be @@ -444,7 +444,7 @@ Vista User Access Control (UAC) =============================== -Starting with Python 2.6, bdist_wininst supports a :option:`--user-access-control` +Starting with Python 2.6, bdist_wininst supports a :option:`!--user-access-control` option. The default is 'none' (meaning no UAC handling is done), and other valid values are 'auto' (meaning prompt for UAC elevation if Python was installed for all users) and 'force' (meaning always prompt for elevation). diff --git a/Doc/distutils/configfile.rst b/Doc/distutils/configfile.rst --- a/Doc/distutils/configfile.rst +++ b/Doc/distutils/configfile.rst @@ -66,7 +66,7 @@ --swig-opts list of SWIG command line options [...] -Note that an option spelled :option:`--foo-bar` on the command-line is spelled +Note that an option spelled :option:`!--foo-bar` on the command-line is spelled ``foo_bar`` in configuration files. .. _distutils-build-ext-inplace: @@ -75,12 +75,12 @@ have an extension :mod:`pkg.ext`, and you want the compiled extension file (:file:`ext.so` on Unix, say) to be put in the same source directory as your pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`--inplace` option on the command-line to ensure this:: +:option:`!--inplace` option on the command-line to ensure this:: python setup.py build_ext --inplace But this requires that you always specify the :command:`build_ext` command -explicitly, and remember to provide :option:`--inplace`. An easier way is to +explicitly, and remember to provide :option:`!--inplace`. An easier way is to "set and forget" this option, by encoding it in :file:`setup.cfg`, the configuration file for this distribution:: diff --git a/Doc/distutils/extending.rst b/Doc/distutils/extending.rst --- a/Doc/distutils/extending.rst +++ b/Doc/distutils/extending.rst @@ -62,7 +62,7 @@ third-party extensions to provide support for additional packaging systems, but the commands can be used for anything distutils commands can be used for. A new configuration option, ``command_packages`` (command-line option -:option:`--command-packages`), can be used to specify additional packages to be +:option:`!--command-packages`), can be used to specify additional packages to be searched for modules implementing commands. Like all distutils options, this can be specified on the command line or in a configuration file. This option can only be set in the ``[global]`` section of a configuration file, or before diff --git a/Doc/distutils/setupscript.rst b/Doc/distutils/setupscript.rst --- a/Doc/distutils/setupscript.rst +++ b/Doc/distutils/setupscript.rst @@ -442,7 +442,7 @@ The only clever feature is that if the first line of the script starts with ``#!`` and contains the word "python", the Distutils will adjust the first line to refer to the current interpreter location. By default, it is replaced with -the current interpreter location. The :option:`--executable` (or :option:`-e`) +the current interpreter location. The :option:`!--executable` (or :option:`!-e`) option will allow the interpreter path to be explicitly overridden. The ``scripts`` option simply is a list of files to be handled in this diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -14,7 +14,7 @@ the current platform. The default format is a gzip'ed tar file (:file:`.tar.gz`) on Unix, and ZIP file on Windows. -You can specify as many formats as you like using the :option:`--formats` +You can specify as many formats as you like using the :option:`!--formats` option, for example:: python setup.py sdist --formats=gztar,zip @@ -147,7 +147,7 @@ in) to create the source distribution archive(s) There are a couple of options that modify this behaviour. First, use the -:option:`--no-defaults` and :option:`--no-prune` to disable the standard +:option:`!--no-defaults` and :option:`!--no-prune` to disable the standard "include" and "exclude" sets. Second, you might just want to (re)generate the manifest, but not create a @@ -155,7 +155,7 @@ python setup.py sdist --manifest-only -:option:`-o` is a shortcut for :option:`--manifest-only`. +:option:`!-o` is a shortcut for :option:`!--manifest-only`. .. _manifest_template: @@ -189,7 +189,7 @@ :file:`examples/sample?/build`. All of this is done *after* the standard include set, so you can exclude files from the standard set with explicit instructions in the manifest template. (Or, you can use the -:option:`--no-defaults` option to disable the standard set entirely.) +:option:`!--no-defaults` option to disable the standard set entirely.) The order of commands in the manifest template matters: initially, we have the list of default files as described above, and each command in the template adds @@ -206,8 +206,8 @@ future reference, and then used to build the source distribution archive(s). You can disable the default set of included files with the -:option:`--no-defaults` option, and you can disable the standard exclude set -with :option:`--no-prune`. +:option:`!--no-defaults` option, and you can disable the standard exclude set +with :option:`!--no-prune`. Following the Distutils' own manifest template, let's trace how the :command:`sdist` command builds the list of files to include in the Distutils diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -858,7 +858,7 @@ :func:`~gc.collect` function), as well as configuration interfaces and the ability to disable the detector at runtime. The cycle detector is considered an optional component; though it is included by default, -it can be disabled at build time using the :option:`--without-cycle-gc` option +it can be disabled at build time using the :option:`!--without-cycle-gc` option to the :program:`configure` script on Unix platforms (including Mac OS X) or by removing the definition of ``WITH_CYCLE_GC`` in the :file:`pyconfig.h` header on other platforms. If the cycle detector is disabled in this way, the :mod:`gc` diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -202,7 +202,7 @@ files to install into a *build directory*. By default, this is :file:`build` under the distribution root; if you're excessively concerned with speed, or want to keep the source tree pristine, you can change the build directory with the -:option:`--build-base` option. For example:: +:option:`!--build-base` option. For example:: python setup.py build --build-base=/path/to/pybuild/foo-1.0 @@ -398,7 +398,7 @@ python setup.py install --home= -where you can supply any directory you like for the :option:`--home` option. On +where you can supply any directory you like for the :option:`!--home` option. On Unix, lazy typists can just type a tilde (``~``); the :command:`install` command will expand this to your home directory:: @@ -409,7 +409,7 @@ :mod:`sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit :data:`sys.path`. -The :option:`--home` option defines the installation base directory. Files are +The :option:`!--home` option defines the installation base directory. Files are installed to the following directories under the installation base as follows: =============== =========================================================== @@ -424,7 +424,7 @@ (Mentally replace slashes with backslashes if you're on Windows.) .. versionchanged:: 2.4 - The :option:`--home` option used to be supported only on Unix. + The :option:`!--home` option used to be supported only on Unix. .. _inst-alt-install-prefix-unix: @@ -457,12 +457,12 @@ /usr/local/bin/python setup.py install --prefix=/mnt/@server/export -In either case, the :option:`--prefix` option defines the installation base, and -the :option:`--exec-prefix` option defines the platform-specific installation +In either case, the :option:`!--prefix` option defines the installation base, and +the :option:`!--exec-prefix` option defines the platform-specific installation base, which is used for platform-specific files. (Currently, this just means non-pure module distributions, but could be expanded to C libraries, binary -executables, etc.) If :option:`--exec-prefix` is not supplied, it defaults to -:option:`--prefix`. Files are installed as follows: +executables, etc.) If :option:`!--exec-prefix` is not supplied, it defaults to +:option:`!--prefix`. Files are installed as follows: ================= ========================================================== Type of file Installation directory @@ -474,13 +474,13 @@ C headers :file:`{prefix}/include/python{X.Y}/{distname}` ================= ========================================================== -There is no requirement that :option:`--prefix` or :option:`--exec-prefix` +There is no requirement that :option:`!--prefix` or :option:`!--exec-prefix` actually point to an alternate Python installation; if the directories listed above do not already exist, they are created at installation time. Incidentally, the real reason the prefix scheme is important is simply that a -standard Unix installation uses the prefix scheme, but with :option:`--prefix` -and :option:`--exec-prefix` supplied by Python itself as ``sys.prefix`` and +standard Unix installation uses the prefix scheme, but with :option:`!--prefix` +and :option:`!--exec-prefix` supplied by Python itself as ``sys.prefix`` and ``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme, but every time you run ``python setup.py install`` without any other options, you're using it. @@ -493,7 +493,7 @@ in this way is compatible with the interpreter used to build them. The best way to do this is to ensure that the two interpreters are the same version of Python (possibly different builds, or possibly copies of the same build). (Of course, -if your :option:`--prefix` and :option:`--exec-prefix` don't even point to an +if your :option:`!--prefix` and :option:`!--exec-prefix` don't even point to an alternate Python installation, this is immaterial.) @@ -503,7 +503,7 @@ --------------------------------------------------- Windows has no concept of a user's home directory, and since the standard Python -installation under Windows is simpler than under Unix, the :option:`--prefix` +installation under Windows is simpler than under Unix, the :option:`!--prefix` option has traditionally been used to install additional packages in separate locations on Windows. :: @@ -511,8 +511,8 @@ to install modules to the :file:`\\Temp\\Python` directory on the current drive. -The installation base is defined by the :option:`--prefix` option; the -:option:`--exec-prefix` option is not supported under Windows, which means that +The installation base is defined by the :option:`!--prefix` option; the +:option:`!--exec-prefix` option is not supported under Windows, which means that pure Python modules and extension modules are installed into the same location. Files are installed as follows: @@ -564,7 +564,7 @@ For example, say you're installing a module distribution to your home directory under Unix---but you want scripts to go in :file:`~/scripts` rather than :file:`~/bin`. As you might expect, you can override this directory with the -:option:`--install-scripts` option; in this case, it makes most sense to supply +:option:`!--install-scripts` option; in this case, it makes most sense to supply a relative path, which will be interpreted relative to the installation base directory (your home directory, in this case):: @@ -574,7 +574,7 @@ with a prefix of :file:`/usr/local/python`, so under a standard installation scripts will wind up in :file:`/usr/local/python/bin`. If you want them in :file:`/usr/local/bin` instead, you would supply this absolute directory for the -:option:`--install-scripts` option:: +:option:`!--install-scripts` option:: python setup.py install --install-scripts=/usr/local/bin @@ -929,10 +929,10 @@ to be in Objective C. * *cpparg* is an argument for the C preprocessor, and is anything starting with - :option:`!-I`, :option:`-D`, :option:`!-U` or :option:`-C`. + :option:`!-I`, :option:`!-D`, :option:`!-U` or :option:`!-C`. -* *library* is anything ending in :file:`.a` or beginning with :option:`-l` or - :option:`-L`. +* *library* is anything ending in :file:`.a` or beginning with :option:`!-l` or + :option:`!-L`. If a particular platform requires a special library on your platform, you can add it by editing the :file:`Setup` file and running ``python setup.py build``. @@ -941,20 +941,20 @@ foo foomodule.c must be linked with the math library :file:`libm.a` on your platform, simply add -:option:`-lm` to the line:: +:option:`!-lm` to the line:: foo foomodule.c -lm Arbitrary switches intended for the compiler or the linker can be supplied with -the :option:`-Xcompiler` *arg* and :option:`-Xlinker` *arg* options:: +the :option:`!-Xcompiler` *arg* and :option:`!-Xlinker` *arg* options:: foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm -The next option after :option:`-Xcompiler` and :option:`-Xlinker` will be +The next option after :option:`!-Xcompiler` and :option:`!-Xlinker` will be appended to the proper command line, so in the above example the compiler will -be passed the :option:`-o32` option, and the linker will be passed -:option:`-shared`. If a compiler option requires an argument, you'll have to -supply multiple :option:`-Xcompiler` options; for example, to pass ``-x c++`` +be passed the :option:`!-o32` option, and the linker will be passed +:option:`!-shared`. If a compiler option requires an argument, you'll have to +supply multiple :option:`!-Xcompiler` options; for example, to pass ``-x c++`` the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``. Compiler flags can also be supplied through setting the :envvar:`CFLAGS` diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst --- a/Doc/library/2to3.rst +++ b/Doc/library/2to3.rst @@ -41,8 +41,8 @@ A diff against the original source file is printed. 2to3 can also write the needed modifications right back to the source file. (A backup of the original -file is made unless :option:`-n` is also given.) Writing the changes back is -enabled with the :option:`-w` flag: +file is made unless :option:`!-n` is also given.) Writing the changes back is +enabled with the :option:`!-w` flag: .. code-block:: shell-session @@ -59,8 +59,8 @@ Comments and exact indentation are preserved throughout the translation process. By default, 2to3 runs a set of :ref:`predefined fixers <2to3-fixers>`. The -:option:`-l` flag lists all available fixers. An explicit set of fixers to run -can be given with :option:`-f`. Likewise the :option:`!-x` explicitly disables a +:option:`!-l` flag lists all available fixers. An explicit set of fixers to run +can be given with :option:`!-f`. Likewise the :option:`!-x` explicitly disables a fixer. The following example runs only the ``imports`` and ``has_key`` fixers: .. code-block:: shell-session @@ -100,29 +100,29 @@ cannot always read files containing the print function. When 2to3 detects the presence of the ``from __future__ import print_function`` compiler directive, it modifies its internal grammar to interpret :func:`print` as a function. This -change can also be enabled manually with the :option:`-p` flag. Use -:option:`-p` to run fixers on code that already has had its print statements +change can also be enabled manually with the :option:`!-p` flag. Use +:option:`!-p` to run fixers on code that already has had its print statements converted. -The :option:`-o` or :option:`--output-dir` option allows specification of an +The :option:`!-o` or :option:`!--output-dir` option allows specification of an alternate directory for processed output files to be written to. The -:option:`-n` flag is required when using this as backup files do not make sense +:option:`!-n` flag is required when using this as backup files do not make sense when not overwriting the input files. .. versionadded:: 2.7.3 - The :option:`-o` option was added. + The :option:`!-o` option was added. -The :option:`!-W` or :option:`--write-unchanged-files` flag tells 2to3 to always +The :option:`!-W` or :option:`!--write-unchanged-files` flag tells 2to3 to always write output files even if no changes were required to the file. This is most -useful with :option:`-o` so that an entire Python source tree is copied with +useful with :option:`!-o` so that an entire Python source tree is copied with translation from one directory to another. -This option implies the :option:`-w` flag as it would not make sense otherwise. +This option implies the :option:`!-w` flag as it would not make sense otherwise. .. versionadded:: 2.7.3 The :option:`!-W` flag was added. -The :option:`--add-suffix` option specifies a string to append to all output -filenames. The :option:`-n` flag is required when specifying this as backups +The :option:`!--add-suffix` option specifies a string to append to all output +filenames. The :option:`!-n` flag is required when specifying this as backups are not necessary when writing to different filenames. Example: .. code-block:: shell-session @@ -132,7 +132,7 @@ Will cause a converted file named ``example.py3`` to be written. .. versionadded:: 2.7.3 - The :option:`--add-suffix` option was added. + The :option:`!--add-suffix` option was added. To translate an entire project from one directory tree to another use: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1302,7 +1302,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like *lib*, suffix like ``.so``, ``.dylib`` or version number (this - is the form used for the posix linker option :option:`-l`). If no library can + is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. @@ -1897,7 +1897,7 @@ Try to find a library and return a pathname. *name* is the library name without any prefix like ``lib``, suffix like ``.so``, ``.dylib`` or version - number (this is the form used for the posix linker option :option:`-l`). If + number (this is the form used for the posix linker option :option:`!-l`). If no library can be found, returns ``None``. The exact functionality is system dependent. diff --git a/Doc/library/easydialogs.rst b/Doc/library/easydialogs.rst --- a/Doc/library/easydialogs.rst +++ b/Doc/library/easydialogs.rst @@ -94,9 +94,9 @@ +----------------------+------------------------------------------+ | ``x:`` or ``x=`` | :option:`!-x` (short option with value) | +----------------------+------------------------------------------+ - | ``xyz`` | :option:`--xyz` (long option) | + | ``xyz`` | :option:`!--xyz` (long option) | +----------------------+------------------------------------------+ - | ``xyz:`` or ``xyz=`` | :option:`--xyz` (long option with value) | + | ``xyz:`` or ``xyz=`` | :option:`!--xyz` (long option with value)| +----------------------+------------------------------------------+ *commandlist* is a list of items of the form *cmdstr* or ``(cmdstr, descr)``, diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -258,13 +258,13 @@ Warnings that are only of interest to the developer are ignored by default. As such you should make sure to test your code with typically ignored warnings made visible. You can do this from the command-line by passing :option:`-Wd <-W>` -to the interpreter (this is shorthand for :option:`-W default`). This enables +to the interpreter (this is shorthand for :option:`!-W default`). This enables default handling for all warnings, including those that are ignored by default. To change what action is taken for encountered warnings you simply change what -argument is passed to :option:`-W`, e.g. :option:`-W error`. See the +argument is passed to :option:`-W`, e.g. :option:`!-W error`. See the :option:`-W` flag for more details on what is possible. -To programmatically do the same as :option:`-Wd`, use:: +To programmatically do the same as :option:`!-Wd`, use:: warnings.simplefilter('default') diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -302,7 +302,7 @@ Issue a warning when a source file mixes tabs and spaces for indentation in a way that makes it depend on the worth of a tab expressed in spaces. Issue an - error when the option is given twice (:option:`-tt`). + error when the option is given twice (:option:`!-tt`). .. cmdoption:: -u @@ -322,7 +322,7 @@ Print a message each time a module is initialized, showing the place (filename or built-in module) from which it is loaded. When given twice - (:option:`-vv`), print a message for each file that is checked for when + (:option:`!-vv`), print a message for each file that is checked for when searching for a module. Also provides information on module cleanup at exit. See also :envvar:`PYTHONVERBOSE`. @@ -344,7 +344,7 @@ invalid options when the first warning is issued). Starting from Python 2.7, :exc:`DeprecationWarning` and its descendants - are ignored by default. The :option:`-Wd` option can be used to re-enable + are ignored by default. The :option:`!-Wd` option can be used to re-enable them. Warnings can also be controlled from within a Python program using the diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -476,7 +476,7 @@ program creates and destroys objects. The detection of cycles can be disabled when Python is compiled, if you can't afford even a tiny speed penalty or suspect that the cycle collection is buggy, by specifying the -:option:`--without-cycle-gc` switch when running the :program:`configure` +:option:`!--without-cycle-gc` switch when running the :program:`configure` script. Several people tackled this problem and contributed to a solution. An early diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -692,7 +692,7 @@ faster than the system :func:`malloc` and have less memory overhead. The allocator uses C's :func:`malloc` function to get large pools of memory, and then fulfills smaller memory requests from these pools. It can be enabled by - providing the :option:`--with-pymalloc` option to the :program:`configure` + providing the :option:`!--with-pymalloc` option to the :program:`configure` script; see :file:`Objects/obmalloc.c` for the implementation details. Authors of C extension modules should test their code with the object allocator diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -779,8 +779,8 @@ Python's Unicode support has been enhanced a bit in 2.2. Unicode strings are usually stored as UCS-2, as 16-bit unsigned integers. Python 2.2 can also be compiled to use UCS-4, 32-bit unsigned integers, as its internal encoding by -supplying :option:`--enable-unicode=ucs4` to the configure script. (It's also -possible to specify :option:`--disable-unicode` to completely disable Unicode +supplying :option:`!--enable-unicode=ucs4` to the configure script. (It's also +possible to specify :option:`!--disable-unicode` to completely disable Unicode support.) When built to use UCS-4 (a "wide Python"), the interpreter can natively handle @@ -979,7 +979,7 @@ output have been corrected. (Contributed by Fred L. Drake, Jr. and Tim Peters.) * The :mod:`socket` module can be compiled to support IPv6; specify the - :option:`--enable-ipv6` option to Python's configure script. (Contributed by + :option:`!--enable-ipv6` option to Python's configure script. (Contributed by Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit @@ -1140,7 +1140,7 @@ in the main Python CVS tree, and many changes have been made to support MacOS X. The most significant change is the ability to build Python as a framework, - enabled by supplying the :option:`--enable-framework` option to the configure + enabled by supplying the :option:`!--enable-framework` option to the configure script when compiling Python. According to Jack Jansen, "This installs a self- contained Python installation plus the OS X framework "glue" into :file:`/Library/Frameworks/Python.framework` (or another location of choice). diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -394,7 +394,7 @@ line-endings. This feature can be disabled when compiling Python by specifying the -:option:`--without-universal-newlines` switch when running Python's +:option:`!--without-universal-newlines` switch when running Python's :program:`configure` script. @@ -1812,9 +1812,9 @@ In 2.1 and 2.2, pymalloc was an experimental feature and wasn't enabled by default; you had to explicitly enable it when compiling Python by providing the -:option:`--with-pymalloc` option to the :program:`configure` script. In 2.3, +:option:`!--with-pymalloc` option to the :program:`configure` script. In 2.3, pymalloc has had further enhancements and is now enabled by default; you'll have -to supply :option:`--without-pymalloc` to disable it. +to supply :option:`!--without-pymalloc` to disable it. This change is transparent to code written in Python; however, pymalloc may expose bugs in C extensions. Authors of C extension modules should test their @@ -1853,7 +1853,7 @@ features to catch memory overwrites and doubled frees in both extension modules and in the interpreter itself. To enable this support, compile a debugging version of the Python interpreter by running :program:`configure` with -:option:`--with-pydebug`. +:option:`!--with-pydebug`. To aid extension writers, a header file :file:`Misc/pymemcompat.h` is distributed with the source to Python 2.3 that allows Python extensions to use @@ -1879,11 +1879,11 @@ * The cycle detection implementation used by the garbage collection has proven to be stable, so it's now been made mandatory. You can no longer compile Python - without it, and the :option:`--with-cycle-gc` switch to :program:`configure` has + without it, and the :option:`!--with-cycle-gc` switch to :program:`configure` has been removed. * Python can now optionally be built as a shared library - (:file:`libpython2.3.so`) by supplying :option:`--enable-shared` when running + (:file:`libpython2.3.so`) by supplying :option:`!--enable-shared` when running Python's :program:`configure` script. (Contributed by Ondrej Palkovsky.) * The :c:macro:`DL_EXPORT` and :c:macro:`DL_IMPORT` macros are now deprecated. @@ -1892,7 +1892,7 @@ generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros. * The interpreter can be compiled without any docstrings for the built-in - functions and modules by supplying :option:`--without-doc-strings` to the + functions and modules by supplying :option:`!--without-doc-strings` to the :program:`configure` script. This makes the Python executable about 10% smaller, but will also mean that you can't get help for Python's built-ins. (Contributed by Gustavo Niemeyer.) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1483,10 +1483,10 @@ * Python can now be built with additional profiling for the interpreter itself, intended as an aid to people developing the Python core. Providing - :option:`--enable-profiling` to the :program:`configure` script will let you + :option:`!--enable-profiling` to the :program:`configure` script will let you profile the interpreter with :program:`gprof`, and providing the - :option:`--with-tsc` switch enables profiling using the Pentium's Time-Stamp- - Counter register. Note that the :option:`--with-tsc` switch is slightly + :option:`!--with-tsc` switch enables profiling using the Pentium's Time-Stamp- + Counter register. Note that the :option:`!--with-tsc` switch is slightly misnamed, because the profiling feature also works on the PowerPC platform, though that processor architecture doesn't call that register "the TSC register". (Contributed by Jeremy Hylton.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -236,7 +236,7 @@ Before a package can be uploaded, you must be able to build a distribution using the :command:`sdist` Distutils command. Once that works, you can run ``python setup.py upload`` to add your package to the PyPI archive. Optionally you can -GPG-sign the package by supplying the :option:`--sign` and :option:`--identity` +GPG-sign the package by supplying the :option:`!--sign` and :option:`!--identity` options. Package uploading was implemented by Martin von L?wis and Richard Jones. @@ -1639,7 +1639,7 @@ * The :mod:`webbrowser` module received a number of enhancements. It's now usable as a script with ``python -m webbrowser``, taking a URL as the argument; - there are a number of switches to control the behaviour (:option:`-n` for a new + there are a number of switches to control the behaviour (:option:`!-n` for a new browser window, :option:`!-t` for a new tab). New module-level functions, :func:`open_new` and :func:`open_new_tab`, were added to support this. The module's :func:`open` function supports an additional feature, an *autoraise* @@ -2209,7 +2209,7 @@ * MacOS X (10.3 and higher): dynamic loading of modules now uses the :c:func:`dlopen` function instead of MacOS-specific functions. -* MacOS X: an :option:`--enable-universalsdk` switch was added to the +* MacOS X: an :option:`!--enable-universalsdk` switch was added to the :program:`configure` script that compiles the interpreter as a universal binary able to run on both PowerPC and Intel processors. (Contributed by Ronald Oussoren; :issue:`2573`.) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2988,7 +2988,7 @@ * On Mac OS X, Python 2.6 can be compiled as a 4-way universal build. The :program:`configure` script - can take a :option:`--with-universal-archs=[32-bit|64-bit|all]` + can take a :option:`!--with-universal-archs=[32-bit|64-bit|all]` switch, controlling whether the binaries are built for 32-bit architectures (x86, PowerPC), 64-bit (x86-64 and PPC-64), or both. (Contributed by Ronald Oussoren.) @@ -3143,7 +3143,7 @@ * When compiling a framework build of Python, you can now specify the framework name to be used by providing the - :option:`--with-framework-name=` option to the + :option:`!--with-framework-name=` option to the :program:`configure` script. * The :mod:`macfs` module has been removed. This in turn required the diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -390,7 +390,7 @@ args = parser.parse_args() print args.__dict__ -Unless you override it, :option:`-h` and :option:`--help` switches +Unless you override it, :option:`!-h` and :option:`!--help` switches are automatically added, and produce neatly formatted output:: -> ./python.exe argparse-example.py --help @@ -945,7 +945,7 @@ benchmark results on 32-bit machines have been mixed. Therefore, the default is to use base 2**30 on 64-bit machines and base 2**15 on 32-bit machines; on Unix, there's a new configure option - :option:`--enable-big-digits` that can be used to override this default. + :option:`!--enable-big-digits` that can be used to override this default. Apart from the performance improvements this change should be invisible to end users, with one exception: for testing and @@ -1820,12 +1820,12 @@ The :func:`~unittest.main` function supports some other new options: -* :option:`-b ` or :option:`--buffer` will buffer the standard output +* :option:`-b ` or :option:`!--buffer` will buffer the standard output and standard error streams during each test. If the test passes, any resulting output will be discarded; on failure, the buffered output will be displayed. -* :option:`-c ` or :option:`--catch` will cause the control-C interrupt +* :option:`-c ` or :option:`!--catch` will cause the control-C interrupt to be handled more gracefully. Instead of interrupting the test process immediately, the currently running test will be completed and then the partial results up to the interruption will be reported. @@ -1839,7 +1839,7 @@ :func:`~unittest.removeHandler` decorator that can be used to mark tests that should have the control-C handling disabled. -* :option:`-f ` or :option:`--failfast` makes +* :option:`-f ` or :option:`!--failfast` makes test execution stop immediately when a test fails instead of continuing to execute further tests. (Suggested by Cliff Dyer and implemented by Michael Foord; :issue:`8074`.) @@ -2214,19 +2214,19 @@ with ``Py``, or with ``_ctypes``. (Implemented by Thomas Heller; :issue:`3102`.) -* New configure option: the :option:`--with-system-expat` switch allows +* New configure option: the :option:`!--with-system-expat` switch allows building the :mod:`pyexpat` module to use the system Expat library. (Contributed by Arfrever Frehtes Taifersar Arahesis; :issue:`7609`.) * New configure option: the - :option:`--with-valgrind` option will now disable the pymalloc + :option:`!--with-valgrind` option will now disable the pymalloc allocator, which is difficult for the Valgrind memory-error detector to analyze correctly. Valgrind will therefore be better at detecting memory leaks and overruns. (Contributed by James Henstridge; :issue:`2422`.) * New configure option: you can now supply an empty string to - :option:`--with-dbmliborder=` in order to disable all of the various + :option:`!--with-dbmliborder=` in order to disable all of the various DBM modules. (Added by Arfrever Frehtes Taifersar Arahesis; :issue:`6491`.) @@ -2373,19 +2373,19 @@ renamed, moved, or is accessed through different paths. (Patch by Ziga Seilnacht and Jean-Paul Calderone; :issue:`1180193`.) -* The :file:`regrtest.py` script now takes a :option:`--randseed=` +* The :file:`regrtest.py` script now takes a :option:`!--randseed=` switch that takes an integer that will be used as the random seed - for the :option:`-r` option that executes tests in random order. - The :option:`-r` option also reports the seed that was used + for the :option:`!-r` option that executes tests in random order. + The :option:`!-r` option also reports the seed that was used (Added by Collin Winter.) -* Another :file:`regrtest.py` switch is :option:`-j`, which +* Another :file:`regrtest.py` switch is :option:`!-j`, which takes an integer specifying how many tests run in parallel. This allows reducing the total runtime on multi-core machines. This option is compatible with several other options, including the :option:`!-R` switch which is known to produce long runtimes. (Added by Antoine Pitrou, :issue:`6152`.) This can also be used - with a new :option:`-F` switch that runs selected tests in a loop + with a new :option:`!-F` switch that runs selected tests in a loop until they fail. (Added by Antoine Pitrou; :issue:`7312`.) * When executed as a script, the :file:`py_compile.py` module now -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 11:28:03 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 15:28:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E5=29=3A_Backed_out_cha?= =?utf-8?q?ngeset_9f7505019767_=28issue_=2327275=29=2E?= Message-ID: <20161030152803.114891.18720.32651D6F@psf.io> https://hg.python.org/cpython/rev/3f816eecc53e changeset: 104817:3f816eecc53e branch: 3.5 parent: 104811:57f4ba6b29bf user: Serhiy Storchaka date: Sun Oct 30 17:17:24 2016 +0200 summary: Backed out changeset 9f7505019767 (issue #27275). files: Lib/test/test_ordered_dict.py | 59 ----------------------- Misc/NEWS | 3 - Objects/odictobject.c | 29 ++++++++-- 3 files changed, 22 insertions(+), 69 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -730,64 +730,5 @@ self.assertRaises(KeyError, d.popitem) -class SimpleLRUCache: - - def __init__(self, size): - super().__init__() - self.size = size - - def __getitem__(self, item): - value = super().__getitem__(item) - self.move_to_end(item) - return value - - def __setitem__(self, key, value): - while key not in self and len(self) >= self.size: - self.popitem(last=False) - super().__setitem__(key, value) - self.move_to_end(key) - - -class SimpleLRUCacheTests: - - def test_add_after_full(self): - c = self.type2test(2) - c['t1'] = 1 - c['t2'] = 2 - c['t3'] = 3 - self.assertEqual(list(c), ['t2', 't3']) - - def test_popitem(self): - c = self.type2test(3) - for i in range(1, 4): - c[i] = i - self.assertEqual(c.popitem(last=False), (1, 1)) - self.assertEqual(c.popitem(last=True), (3, 3)) - - def test_change_order_on_get(self): - c = self.type2test(3) - for i in range(1, 4): - c[i] = i - self.assertEqual(list(c), list(range(1, 4))) - self.assertEqual(c[2], 2) - self.assertEqual(list(c), [1, 3, 2]) - - -class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): - - class type2test(SimpleLRUCache, py_coll.OrderedDict): - pass - - - at unittest.skipUnless(c_coll, 'requires the C version of the collections module') -class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): - - @classmethod - def setUpClass(cls): - class type2test(SimpleLRUCache, c_coll.OrderedDict): - pass - cls.type2test = type2test - - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,9 +113,6 @@ Library ------- -- Issue #27275: Fixed implementation of pop() and popitem() methods in - subclasses of accelerated OrderedDict. - - Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1099,13 +1099,28 @@ } /* Now delete the value from the dict. */ - if (node != NULL) { - value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ - if (value != NULL) { - Py_INCREF(value); - if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { - Py_DECREF(value); - return NULL; + if (PyODict_CheckExact(od)) { + if (node != NULL) { + value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ + if (value != NULL) { + Py_INCREF(value); + if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { + Py_DECREF(value); + return NULL; + } + } + } + } + else { + int exists = PySequence_Contains(od, key); + if (exists < 0) + return NULL; + if (exists) { + value = PyObject_GetItem(od, key); + if (value != NULL) { + if (PyObject_DelItem(od, key) == -1) { + Py_CLEAR(value); + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 11:28:05 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 15:28:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Merge_from_3=2E5=2E?= Message-ID: <20161030152803.31729.30918.18A6D724@psf.io> https://hg.python.org/cpython/rev/e7b768717074 changeset: 104818:e7b768717074 branch: 3.6 parent: 104812:a0d272fbc7de parent: 104817:3f816eecc53e user: Serhiy Storchaka date: Sun Oct 30 17:25:45 2016 +0200 summary: Merge from 3.5. files: Lib/test/test_ordered_dict.py | 59 ----------------------- Misc/NEWS | 3 - Objects/odictobject.c | 29 ++++++++-- 3 files changed, 22 insertions(+), 69 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -775,64 +775,5 @@ self.assertRaises(KeyError, d.popitem) -class SimpleLRUCache: - - def __init__(self, size): - super().__init__() - self.size = size - - def __getitem__(self, item): - value = super().__getitem__(item) - self.move_to_end(item) - return value - - def __setitem__(self, key, value): - while key not in self and len(self) >= self.size: - self.popitem(last=False) - super().__setitem__(key, value) - self.move_to_end(key) - - -class SimpleLRUCacheTests: - - def test_add_after_full(self): - c = self.type2test(2) - c['t1'] = 1 - c['t2'] = 2 - c['t3'] = 3 - self.assertEqual(list(c), ['t2', 't3']) - - def test_popitem(self): - c = self.type2test(3) - for i in range(1, 4): - c[i] = i - self.assertEqual(c.popitem(last=False), (1, 1)) - self.assertEqual(c.popitem(last=True), (3, 3)) - - def test_change_order_on_get(self): - c = self.type2test(3) - for i in range(1, 4): - c[i] = i - self.assertEqual(list(c), list(range(1, 4))) - self.assertEqual(c[2], 2) - self.assertEqual(list(c), [1, 3, 2]) - - -class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): - - class type2test(SimpleLRUCache, py_coll.OrderedDict): - pass - - - at unittest.skipUnless(c_coll, 'requires the C version of the collections module') -class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): - - @classmethod - def setUpClass(cls): - class type2test(SimpleLRUCache, c_coll.OrderedDict): - pass - cls.type2test = type2test - - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,9 +31,6 @@ Library ------- -- Issue #27275: Fixed implementation of pop() and popitem() methods in - subclasses of accelerated OrderedDict. - - Issue #18844: The various ways of specifing weights for random.choices() now produce the same result sequences. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1102,13 +1102,28 @@ } /* Now delete the value from the dict. */ - if (node != NULL) { - value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ - if (value != NULL) { - Py_INCREF(value); - if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { - Py_DECREF(value); - return NULL; + if (PyODict_CheckExact(od)) { + if (node != NULL) { + value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ + if (value != NULL) { + Py_INCREF(value); + if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { + Py_DECREF(value); + return NULL; + } + } + } + } + else { + int exists = PySequence_Contains(od, key); + if (exists < 0) + return NULL; + if (exists) { + value = PyObject_GetItem(od, key); + if (value != NULL) { + if (PyObject_DelItem(od, key) == -1) { + Py_CLEAR(value); + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 11:28:05 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 15:28:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjYu?= Message-ID: <20161030152803.3444.18126.9ED994A5@psf.io> https://hg.python.org/cpython/rev/d48de4152b59 changeset: 104819:d48de4152b59 parent: 104813:85e2cfe5b12d parent: 104818:e7b768717074 user: Serhiy Storchaka date: Sun Oct 30 17:27:40 2016 +0200 summary: Merge from 3.6. files: Lib/test/test_ordered_dict.py | 59 ----------------------- Misc/NEWS | 3 - Objects/odictobject.c | 29 ++++++++-- 3 files changed, 22 insertions(+), 69 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -775,64 +775,5 @@ self.assertRaises(KeyError, d.popitem) -class SimpleLRUCache: - - def __init__(self, size): - super().__init__() - self.size = size - - def __getitem__(self, item): - value = super().__getitem__(item) - self.move_to_end(item) - return value - - def __setitem__(self, key, value): - while key not in self and len(self) >= self.size: - self.popitem(last=False) - super().__setitem__(key, value) - self.move_to_end(key) - - -class SimpleLRUCacheTests: - - def test_add_after_full(self): - c = self.type2test(2) - c['t1'] = 1 - c['t2'] = 2 - c['t3'] = 3 - self.assertEqual(list(c), ['t2', 't3']) - - def test_popitem(self): - c = self.type2test(3) - for i in range(1, 4): - c[i] = i - self.assertEqual(c.popitem(last=False), (1, 1)) - self.assertEqual(c.popitem(last=True), (3, 3)) - - def test_change_order_on_get(self): - c = self.type2test(3) - for i in range(1, 4): - c[i] = i - self.assertEqual(list(c), list(range(1, 4))) - self.assertEqual(c[2], 2) - self.assertEqual(list(c), [1, 3, 2]) - - -class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): - - class type2test(SimpleLRUCache, py_coll.OrderedDict): - pass - - - at unittest.skipUnless(c_coll, 'requires the C version of the collections module') -class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): - - @classmethod - def setUpClass(cls): - class type2test(SimpleLRUCache, c_coll.OrderedDict): - pass - cls.type2test = type2test - - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,9 +99,6 @@ Library ------- -- Issue #27275: Fixed implementation of pop() and popitem() methods in - subclasses of accelerated OrderedDict. - - Issue #28255: calendar.TextCalendar.prweek() no longer prints a space after a weeks's calendar. calendar.TextCalendar.pryear() no longer prints redundant newline after a year's calendar. Based on patch by Xiang Zhang. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1102,13 +1102,28 @@ } /* Now delete the value from the dict. */ - if (node != NULL) { - value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ - if (value != NULL) { - Py_INCREF(value); - if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { - Py_DECREF(value); - return NULL; + if (PyODict_CheckExact(od)) { + if (node != NULL) { + value = _PyDict_GetItem_KnownHash(od, key, hash); /* borrowed */ + if (value != NULL) { + Py_INCREF(value); + if (_PyDict_DelItem_KnownHash(od, key, hash) < 0) { + Py_DECREF(value); + return NULL; + } + } + } + } + else { + int exists = PySequence_Contains(od, key); + if (exists < 0) + return NULL; + if (exists) { + value = PyObject_GetItem(od, key); + if (value != NULL) { + if (PyObject_DelItem(od, key) == -1) { + Py_CLEAR(value); + } } } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 12:26:14 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 16:26:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTYx?= =?utf-8?q?=3A_Clean_up_UTF-8_encoder=3A_remove_dead_code=2C_update_commen?= =?utf-8?q?ts=2C_etc=2E?= Message-ID: <20161030162614.3444.59369.1AD9F905@psf.io> https://hg.python.org/cpython/rev/542065b03c10 changeset: 104820:542065b03c10 branch: 3.6 parent: 104818:e7b768717074 user: Serhiy Storchaka date: Sun Oct 30 18:25:27 2016 +0200 summary: Issue #28561: Clean up UTF-8 encoder: remove dead code, update comments, etc. Patch by Xiang Zhang. files: Objects/stringlib/codecs.h | 14 ++++---------- 1 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h --- a/Objects/stringlib/codecs.h +++ b/Objects/stringlib/codecs.h @@ -262,9 +262,7 @@ Py_ssize_t size, const char *errors) { -#define MAX_SHORT_UNICHARS 300 /* largest size we'll do on the stack */ - - Py_ssize_t i; /* index into s of next input byte */ + Py_ssize_t i; /* index into data of next input character */ char *p; /* next free byte in output buffer */ #if STRINGLIB_SIZEOF_CHAR > 1 PyObject *error_handler_obj = NULL; @@ -389,7 +387,7 @@ goto error; /* subtract preallocated bytes */ - writer.min_size -= max_char_size; + writer.min_size -= max_char_size * (newpos - startpos); if (PyBytes_Check(rep)) { p = _PyBytesWriter_WriteBytes(&writer, p, @@ -402,14 +400,12 @@ goto error; if (!PyUnicode_IS_ASCII(rep)) { - raise_encode_exception(&exc, "utf-8", - unicode, - i-1, i, + raise_encode_exception(&exc, "utf-8", unicode, + startpos, endpos, "surrogates not allowed"); goto error; } - assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); p = _PyBytesWriter_WriteBytes(&writer, p, PyUnicode_DATA(rep), PyUnicode_GET_LENGTH(rep)); @@ -463,8 +459,6 @@ _PyBytesWriter_Dealloc(&writer); return NULL; #endif - -#undef MAX_SHORT_UNICHARS } /* The pattern for constructing UCS2-repeated masks. */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 12:26:15 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 16:26:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328561=3A_Clean_up_UTF-8_encoder=3A_remove_dead_?= =?utf-8?q?code=2C_update_comments=2C_etc=2E?= Message-ID: <20161030162615.25747.4524.23340711@psf.io> https://hg.python.org/cpython/rev/ee3670d9bda6 changeset: 104821:ee3670d9bda6 parent: 104819:d48de4152b59 parent: 104820:542065b03c10 user: Serhiy Storchaka date: Sun Oct 30 18:25:46 2016 +0200 summary: Issue #28561: Clean up UTF-8 encoder: remove dead code, update comments, etc. Patch by Xiang Zhang. files: Objects/stringlib/codecs.h | 14 ++++---------- 1 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h --- a/Objects/stringlib/codecs.h +++ b/Objects/stringlib/codecs.h @@ -262,9 +262,7 @@ Py_ssize_t size, const char *errors) { -#define MAX_SHORT_UNICHARS 300 /* largest size we'll do on the stack */ - - Py_ssize_t i; /* index into s of next input byte */ + Py_ssize_t i; /* index into data of next input character */ char *p; /* next free byte in output buffer */ #if STRINGLIB_SIZEOF_CHAR > 1 PyObject *error_handler_obj = NULL; @@ -389,7 +387,7 @@ goto error; /* subtract preallocated bytes */ - writer.min_size -= max_char_size; + writer.min_size -= max_char_size * (newpos - startpos); if (PyBytes_Check(rep)) { p = _PyBytesWriter_WriteBytes(&writer, p, @@ -402,14 +400,12 @@ goto error; if (!PyUnicode_IS_ASCII(rep)) { - raise_encode_exception(&exc, "utf-8", - unicode, - i-1, i, + raise_encode_exception(&exc, "utf-8", unicode, + startpos, endpos, "surrogates not allowed"); goto error; } - assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); p = _PyBytesWriter_WriteBytes(&writer, p, PyUnicode_DATA(rep), PyUnicode_GET_LENGTH(rep)); @@ -463,8 +459,6 @@ _PyBytesWriter_Dealloc(&writer); return NULL; #endif - -#undef MAX_SHORT_UNICHARS } /* The pattern for constructing UCS2-repeated masks. */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 12:53:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 16:53:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3OTM5?= =?utf-8?q?=3A_Fixed_bugs_in_tkinter=2Ettk=2ELabeledScale_and_tkinter=2ESc?= =?utf-8?q?ale_caused?= Message-ID: <20161030165325.62716.57383.4499AFD6@psf.io> https://hg.python.org/cpython/rev/394b2b4da150 changeset: 104822:394b2b4da150 branch: 3.5 parent: 104817:3f816eecc53e user: Serhiy Storchaka date: Sun Oct 30 18:49:52 2016 +0200 summary: Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused by representing the scale as float value internally in Tk. tkinter.IntVar now works if float value is set to underlying Tk variable. files: Lib/tkinter/__init__.py | 8 +++- Lib/tkinter/test/test_tkinter/test_variables.py | 5 +- Lib/tkinter/test/test_ttk/test_extensions.py | 17 +++++++-- Misc/NEWS | 4 ++ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -357,7 +357,11 @@ def get(self): """Return the value of the variable as an integer.""" - return self._tk.getint(self._tk.globalgetvar(self._name)) + value = self._tk.globalgetvar(self._name) + try: + return self._tk.getint(value) + except (TypeError, TclError): + return int(self._tk.getdouble(value)) class DoubleVar(Variable): """Value holder for float variables.""" @@ -2864,7 +2868,7 @@ value = self.tk.call(self._w, 'get') try: return self.tk.getint(value) - except (ValueError, TclError): + except (ValueError, TypeError, TclError): return self.tk.getdouble(value) def set(self, value): """Set the value to VALUE.""" diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py --- a/Lib/tkinter/test/test_tkinter/test_variables.py +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -167,15 +167,14 @@ self.assertEqual(123, v.get()) self.root.globalsetvar("name", "345") self.assertEqual(345, v.get()) + self.root.globalsetvar("name", "876.5") + self.assertEqual(876, v.get()) def test_invalid_value(self): v = IntVar(self.root, name="name") self.root.globalsetvar("name", "value") with self.assertRaises((ValueError, TclError)): v.get() - self.root.globalsetvar("name", "345.0") - with self.assertRaises((ValueError, TclError)): - v.get() class TestDoubleVar(TestBase): diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -69,14 +69,12 @@ # variable initialization/passing passed_expected = (('0', 0), (0, 0), (10, 10), - (-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) + (-1, -1), (sys.maxsize + 1, sys.maxsize + 1), + (2.5, 2), ('2.5', 2)) for pair in passed_expected: x = ttk.LabeledScale(self.root, from_=pair[0]) self.assertEqual(x.value, pair[1]) x.destroy() - x = ttk.LabeledScale(self.root, from_='2.5') - self.assertRaises((ValueError, tkinter.TclError), x._variable.get) - x.destroy() x = ttk.LabeledScale(self.root, from_=None) self.assertRaises((ValueError, tkinter.TclError), x._variable.get) x.destroy() @@ -155,8 +153,10 @@ # The following update is needed since the test doesn't use mainloop, # at the same time this shouldn't affect test outcome x.update() + self.assertEqual(x.value, newval) self.assertEqual(x.label['text'], newval if self.wantobjects else str(newval)) + self.assertEqual(float(x.scale.get()), newval) self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) @@ -168,10 +168,19 @@ conv = int x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen x.update() + self.assertEqual(x.value, newval) self.assertEqual(conv(x.label['text']), newval) + self.assertEqual(float(x.scale.get()), newval) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) + # non-integer value + x.value = newval = newval + 1.5 + x.update() + self.assertEqual(x.value, int(newval)) + self.assertEqual(conv(x.label['text']), int(newval)) + self.assertEqual(float(x.scale.get()), newval) + x.destroy() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,10 @@ Library ------- +- Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused + by representing the scale as float value internally in Tk. tkinter.IntVar + now works if float value is set to underlying Tk variable. + - Issue #28255: calendar.TextCalendar().prmonth() no longer prints a space at the start of new line after printing a month's calendar. Patch by Xiang Zhang. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 12:53:25 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 16:53:25 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2327939=3A_Fixed_bugs_in_tkinter=2Ettk=2ELabeledScale_a?= =?utf-8?q?nd_tkinter=2EScale_caused?= Message-ID: <20161030165325.25505.77815.9E8062E4@psf.io> https://hg.python.org/cpython/rev/91884d043fdc changeset: 104823:91884d043fdc branch: 3.6 parent: 104820:542065b03c10 parent: 104822:394b2b4da150 user: Serhiy Storchaka date: Sun Oct 30 18:52:02 2016 +0200 summary: Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused by representing the scale as float value internally in Tk. tkinter.IntVar now works if float value is set to underlying Tk variable. files: Lib/tkinter/__init__.py | 8 +++- Lib/tkinter/test/test_tkinter/test_variables.py | 5 +- Lib/tkinter/test/test_ttk/test_extensions.py | 17 +++++++-- Misc/NEWS | 4 ++ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -500,7 +500,11 @@ def get(self): """Return the value of the variable as an integer.""" - return self._tk.getint(self._tk.globalgetvar(self._name)) + value = self._tk.globalgetvar(self._name) + try: + return self._tk.getint(value) + except (TypeError, TclError): + return int(self._tk.getdouble(value)) class DoubleVar(Variable): """Value holder for float variables.""" @@ -3003,7 +3007,7 @@ value = self.tk.call(self._w, 'get') try: return self.tk.getint(value) - except (ValueError, TclError): + except (ValueError, TypeError, TclError): return self.tk.getdouble(value) def set(self, value): """Set the value to VALUE.""" diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py --- a/Lib/tkinter/test/test_tkinter/test_variables.py +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -217,15 +217,14 @@ self.assertEqual(123, v.get()) self.root.globalsetvar("name", "345") self.assertEqual(345, v.get()) + self.root.globalsetvar("name", "876.5") + self.assertEqual(876, v.get()) def test_invalid_value(self): v = IntVar(self.root, name="name") self.root.globalsetvar("name", "value") with self.assertRaises((ValueError, TclError)): v.get() - self.root.globalsetvar("name", "345.0") - with self.assertRaises((ValueError, TclError)): - v.get() class TestDoubleVar(TestBase): diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -69,14 +69,12 @@ # variable initialization/passing passed_expected = (('0', 0), (0, 0), (10, 10), - (-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) + (-1, -1), (sys.maxsize + 1, sys.maxsize + 1), + (2.5, 2), ('2.5', 2)) for pair in passed_expected: x = ttk.LabeledScale(self.root, from_=pair[0]) self.assertEqual(x.value, pair[1]) x.destroy() - x = ttk.LabeledScale(self.root, from_='2.5') - self.assertRaises((ValueError, tkinter.TclError), x._variable.get) - x.destroy() x = ttk.LabeledScale(self.root, from_=None) self.assertRaises((ValueError, tkinter.TclError), x._variable.get) x.destroy() @@ -155,8 +153,10 @@ # The following update is needed since the test doesn't use mainloop, # at the same time this shouldn't affect test outcome x.update() + self.assertEqual(x.value, newval) self.assertEqual(x.label['text'], newval if self.wantobjects else str(newval)) + self.assertEqual(float(x.scale.get()), newval) self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) @@ -168,10 +168,19 @@ conv = int x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen x.update() + self.assertEqual(x.value, newval) self.assertEqual(conv(x.label['text']), newval) + self.assertEqual(float(x.scale.get()), newval) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) + # non-integer value + x.value = newval = newval + 1.5 + x.update() + self.assertEqual(x.value, int(newval)) + self.assertEqual(conv(x.label['text']), int(newval)) + self.assertEqual(float(x.scale.get()), newval) + x.destroy() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,10 @@ Library ------- +- Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused + by representing the scale as float value internally in Tk. tkinter.IntVar + now works if float value is set to underlying Tk variable. + - Issue #18844: The various ways of specifing weights for random.choices() now produce the same result sequences. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 12:53:26 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 16:53:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327939=3A_Fixed_bugs_in_tkinter=2Ettk=2ELabeledS?= =?utf-8?q?cale_and_tkinter=2EScale_caused?= Message-ID: <20161030165325.45023.86981.458C3C86@psf.io> https://hg.python.org/cpython/rev/9e3931aa1ff0 changeset: 104824:9e3931aa1ff0 parent: 104821:ee3670d9bda6 parent: 104823:91884d043fdc user: Serhiy Storchaka date: Sun Oct 30 18:53:09 2016 +0200 summary: Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused by representing the scale as float value internally in Tk. tkinter.IntVar now works if float value is set to underlying Tk variable. files: Lib/tkinter/__init__.py | 8 +++- Lib/tkinter/test/test_tkinter/test_variables.py | 5 +- Lib/tkinter/test/test_ttk/test_extensions.py | 17 +++++++-- Misc/NEWS | 4 ++ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -500,7 +500,11 @@ def get(self): """Return the value of the variable as an integer.""" - return self._tk.getint(self._tk.globalgetvar(self._name)) + value = self._tk.globalgetvar(self._name) + try: + return self._tk.getint(value) + except (TypeError, TclError): + return int(self._tk.getdouble(value)) class DoubleVar(Variable): """Value holder for float variables.""" @@ -3003,7 +3007,7 @@ value = self.tk.call(self._w, 'get') try: return self.tk.getint(value) - except (ValueError, TclError): + except (ValueError, TypeError, TclError): return self.tk.getdouble(value) def set(self, value): """Set the value to VALUE.""" diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py --- a/Lib/tkinter/test/test_tkinter/test_variables.py +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -217,15 +217,14 @@ self.assertEqual(123, v.get()) self.root.globalsetvar("name", "345") self.assertEqual(345, v.get()) + self.root.globalsetvar("name", "876.5") + self.assertEqual(876, v.get()) def test_invalid_value(self): v = IntVar(self.root, name="name") self.root.globalsetvar("name", "value") with self.assertRaises((ValueError, TclError)): v.get() - self.root.globalsetvar("name", "345.0") - with self.assertRaises((ValueError, TclError)): - v.get() class TestDoubleVar(TestBase): diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -69,14 +69,12 @@ # variable initialization/passing passed_expected = (('0', 0), (0, 0), (10, 10), - (-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) + (-1, -1), (sys.maxsize + 1, sys.maxsize + 1), + (2.5, 2), ('2.5', 2)) for pair in passed_expected: x = ttk.LabeledScale(self.root, from_=pair[0]) self.assertEqual(x.value, pair[1]) x.destroy() - x = ttk.LabeledScale(self.root, from_='2.5') - self.assertRaises((ValueError, tkinter.TclError), x._variable.get) - x.destroy() x = ttk.LabeledScale(self.root, from_=None) self.assertRaises((ValueError, tkinter.TclError), x._variable.get) x.destroy() @@ -155,8 +153,10 @@ # The following update is needed since the test doesn't use mainloop, # at the same time this shouldn't affect test outcome x.update() + self.assertEqual(x.value, newval) self.assertEqual(x.label['text'], newval if self.wantobjects else str(newval)) + self.assertEqual(float(x.scale.get()), newval) self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) @@ -168,10 +168,19 @@ conv = int x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen x.update() + self.assertEqual(x.value, newval) self.assertEqual(conv(x.label['text']), newval) + self.assertEqual(float(x.scale.get()), newval) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) + # non-integer value + x.value = newval = newval + 1.5 + x.update() + self.assertEqual(x.value, int(newval)) + self.assertEqual(conv(x.label['text']), int(newval)) + self.assertEqual(float(x.scale.get()), newval) + x.destroy() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,10 @@ Library ------- +- Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused + by representing the scale as float value internally in Tk. tkinter.IntVar + now works if float value is set to underlying Tk variable. + - Issue #28255: calendar.TextCalendar.prweek() no longer prints a space after a weeks's calendar. calendar.TextCalendar.pryear() no longer prints redundant newline after a year's calendar. Based on patch by Xiang Zhang. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 13:22:32 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 17:22:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzIzMjYy?= =?utf-8?q?=3A_The_webbrowser_module_now_supports_Firefox_36+_and_derived?= Message-ID: <20161030172232.7977.84256.3ED669CD@psf.io> https://hg.python.org/cpython/rev/dacb52577c1c changeset: 104825:dacb52577c1c branch: 3.5 parent: 104822:394b2b4da150 user: Serhiy Storchaka date: Sun Oct 30 19:16:33 2016 +0200 summary: Issue #23262: The webbrowser module now supports Firefox 36+ and derived browsers. Based on patch by Oleg Broytman. files: Lib/test/test_webbrowser.py | 25 ++++++++++++++++++++++ Lib/webbrowser.py | 28 +++++++++++++++++------- Misc/NEWS | 3 ++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -95,6 +95,31 @@ def test_open(self): self._test('open', + options=[], + arguments=[URL]) + + def test_open_with_autoraise_false(self): + self._test('open', kw=dict(autoraise=False), + options=[], + arguments=[URL]) + + def test_open_new(self): + self._test('open_new', + options=[], + arguments=['-new-window', URL]) + + def test_open_new_tab(self): + self._test('open_new_tab', + options=[], + arguments=['-new-tab', URL]) + + +class NetscapeCommandTest(CommandTestMixin, unittest.TestCase): + + browser_class = webbrowser.Netscape + + def test_open(self): + self._test('open', options=['-raise', '-remote'], arguments=['openURL({})'.format(URL)]) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -245,7 +245,17 @@ class Mozilla(UnixBrowser): - """Launcher class for Mozilla/Netscape browsers.""" + """Launcher class for Mozilla browsers.""" + + remote_args = ['%action', '%s'] + remote_action = "" + remote_action_newwin = "-new-window" + remote_action_newtab = "-new-tab" + background = True + + +class Netscape(UnixBrowser): + """Launcher class for Netscape browser.""" raise_opts = ["-noraise", "-raise"] remote_args = ['-remote', 'openURL(%s%action)'] @@ -254,8 +264,6 @@ remote_action_newtab = ",new-tab" background = True -Netscape = Mozilla - class Galeon(UnixBrowser): """Launcher class for Galeon/Epiphany browsers.""" @@ -430,14 +438,18 @@ if shutil.which("x-www-browser"): register("x-www-browser", None, BackgroundBrowser("x-www-browser")) - # The Mozilla/Netscape browsers - for browser in ("mozilla-firefox", "firefox", - "mozilla-firebird", "firebird", - "iceweasel", "iceape", - "seamonkey", "mozilla", "netscape"): + # The Mozilla browsers + for browser in ("firefox", "iceweasel", "iceape", "seamonkey"): if shutil.which(browser): register(browser, None, Mozilla(browser)) + # The Netscape and old Mozilla browsers + for browser in ("mozilla-firefox", + "mozilla-firebird", "firebird", + "mozilla", "netscape"): + if shutil.which(browser): + register(browser, None, Netscape(browser)) + # Konqueror/kfm, the KDE browser. if shutil.which("kfm"): register("kfm", Konqueror, Konqueror("kfm")) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #23262: The webbrowser module now supports Firefox 36+ and derived + browsers. Based on patch by Oleg Broytman. + - Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused by representing the scale as float value internally in Tk. tkinter.IntVar now works if float value is set to underlying Tk variable. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 13:22:32 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 17:22:32 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323262=3A_The_webbrowser_module_now_supports_Fir?= =?utf-8?q?efox_36+_and_derived?= Message-ID: <20161030172232.7144.58359.8A95FEE2@psf.io> https://hg.python.org/cpython/rev/cade42bd0ee0 changeset: 104827:cade42bd0ee0 parent: 104824:9e3931aa1ff0 parent: 104826:f1abc92a756a user: Serhiy Storchaka date: Sun Oct 30 19:22:15 2016 +0200 summary: Issue #23262: The webbrowser module now supports Firefox 36+ and derived browsers. Based on patch by Oleg Broytman. files: Lib/test/test_webbrowser.py | 25 ++++++++++++++++++++++ Lib/webbrowser.py | 28 +++++++++++++++++------- Misc/NEWS | 3 ++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -95,6 +95,31 @@ def test_open(self): self._test('open', + options=[], + arguments=[URL]) + + def test_open_with_autoraise_false(self): + self._test('open', kw=dict(autoraise=False), + options=[], + arguments=[URL]) + + def test_open_new(self): + self._test('open_new', + options=[], + arguments=['-new-window', URL]) + + def test_open_new_tab(self): + self._test('open_new_tab', + options=[], + arguments=['-new-tab', URL]) + + +class NetscapeCommandTest(CommandTestMixin, unittest.TestCase): + + browser_class = webbrowser.Netscape + + def test_open(self): + self._test('open', options=['-raise', '-remote'], arguments=['openURL({})'.format(URL)]) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -245,7 +245,17 @@ class Mozilla(UnixBrowser): - """Launcher class for Mozilla/Netscape browsers.""" + """Launcher class for Mozilla browsers.""" + + remote_args = ['%action', '%s'] + remote_action = "" + remote_action_newwin = "-new-window" + remote_action_newtab = "-new-tab" + background = True + + +class Netscape(UnixBrowser): + """Launcher class for Netscape browser.""" raise_opts = ["-noraise", "-raise"] remote_args = ['-remote', 'openURL(%s%action)'] @@ -254,8 +264,6 @@ remote_action_newtab = ",new-tab" background = True -Netscape = Mozilla - class Galeon(UnixBrowser): """Launcher class for Galeon/Epiphany browsers.""" @@ -430,14 +438,18 @@ if shutil.which("x-www-browser"): register("x-www-browser", None, BackgroundBrowser("x-www-browser")) - # The Mozilla/Netscape browsers - for browser in ("mozilla-firefox", "firefox", - "mozilla-firebird", "firebird", - "iceweasel", "iceape", - "seamonkey", "mozilla", "netscape"): + # The Mozilla browsers + for browser in ("firefox", "iceweasel", "iceape", "seamonkey"): if shutil.which(browser): register(browser, None, Mozilla(browser)) + # The Netscape and old Mozilla browsers + for browser in ("mozilla-firefox", + "mozilla-firebird", "firebird", + "mozilla", "netscape"): + if shutil.which(browser): + register(browser, None, Netscape(browser)) + # Konqueror/kfm, the KDE browser. if shutil.which("kfm"): register("kfm", Konqueror, Konqueror("kfm")) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,9 @@ Library ------- +- Issue #23262: The webbrowser module now supports Firefox 36+ and derived + browsers. Based on patch by Oleg Broytman. + - Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused by representing the scale as float value internally in Tk. tkinter.IntVar now works if float value is set to underlying Tk variable. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 13:22:32 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 17:22:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_-_Issue_=2323262=3A_The_webbrowser_module_now_supports_Firefox?= =?utf-8?q?_36+_and_derived?= Message-ID: <20161030172232.25480.72764.B7DC6916@psf.io> https://hg.python.org/cpython/rev/f1abc92a756a changeset: 104826:f1abc92a756a branch: 3.6 parent: 104823:91884d043fdc parent: 104825:dacb52577c1c user: Serhiy Storchaka date: Sun Oct 30 19:21:10 2016 +0200 summary: - Issue #23262: The webbrowser module now supports Firefox 36+ and derived browsers. Based on patch by Oleg Broytman. files: Lib/test/test_webbrowser.py | 25 ++++++++++++++++++++++ Lib/webbrowser.py | 28 +++++++++++++++++------- Misc/NEWS | 3 ++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -95,6 +95,31 @@ def test_open(self): self._test('open', + options=[], + arguments=[URL]) + + def test_open_with_autoraise_false(self): + self._test('open', kw=dict(autoraise=False), + options=[], + arguments=[URL]) + + def test_open_new(self): + self._test('open_new', + options=[], + arguments=['-new-window', URL]) + + def test_open_new_tab(self): + self._test('open_new_tab', + options=[], + arguments=['-new-tab', URL]) + + +class NetscapeCommandTest(CommandTestMixin, unittest.TestCase): + + browser_class = webbrowser.Netscape + + def test_open(self): + self._test('open', options=['-raise', '-remote'], arguments=['openURL({})'.format(URL)]) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -245,7 +245,17 @@ class Mozilla(UnixBrowser): - """Launcher class for Mozilla/Netscape browsers.""" + """Launcher class for Mozilla browsers.""" + + remote_args = ['%action', '%s'] + remote_action = "" + remote_action_newwin = "-new-window" + remote_action_newtab = "-new-tab" + background = True + + +class Netscape(UnixBrowser): + """Launcher class for Netscape browser.""" raise_opts = ["-noraise", "-raise"] remote_args = ['-remote', 'openURL(%s%action)'] @@ -254,8 +264,6 @@ remote_action_newtab = ",new-tab" background = True -Netscape = Mozilla - class Galeon(UnixBrowser): """Launcher class for Galeon/Epiphany browsers.""" @@ -430,14 +438,18 @@ if shutil.which("x-www-browser"): register("x-www-browser", None, BackgroundBrowser("x-www-browser")) - # The Mozilla/Netscape browsers - for browser in ("mozilla-firefox", "firefox", - "mozilla-firebird", "firebird", - "iceweasel", "iceape", - "seamonkey", "mozilla", "netscape"): + # The Mozilla browsers + for browser in ("firefox", "iceweasel", "iceape", "seamonkey"): if shutil.which(browser): register(browser, None, Mozilla(browser)) + # The Netscape and old Mozilla browsers + for browser in ("mozilla-firefox", + "mozilla-firebird", "firebird", + "mozilla", "netscape"): + if shutil.which(browser): + register(browser, None, Netscape(browser)) + # Konqueror/kfm, the KDE browser. if shutil.which("kfm"): register("kfm", Konqueror, Konqueror("kfm")) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ Library ------- +- Issue #23262: The webbrowser module now supports Firefox 36+ and derived + browsers. Based on patch by Oleg Broytman. + - Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused by representing the scale as float value internally in Tk. tkinter.IntVar now works if float value is set to underlying Tk variable. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 13:38:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 17:38:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4Mzg1?= =?utf-8?q?=3A_An_error_message_when_non-empty_format_spec_is_passed_to?= Message-ID: <20161030173843.114864.69488.7E09AF93@psf.io> https://hg.python.org/cpython/rev/92cae79fa5d9 changeset: 104828:92cae79fa5d9 branch: 3.5 parent: 104825:dacb52577c1c user: Serhiy Storchaka date: Sun Oct 30 19:33:54 2016 +0200 summary: Issue #28385: An error message when non-empty format spec is passed to object.__format__ now contains the name of actual type. files: Lib/test/test_builtin.py | 24 ++++++++++------------ Lib/test/test_bytes.py | 9 ++++++++ Objects/typeobject.c | 30 +++++++++------------------ 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -11,6 +11,7 @@ import pickle import platform import random +import re import sys import traceback import types @@ -1447,21 +1448,14 @@ # -------------------------------------------------------------------- # Issue #7994: object.__format__ with a non-empty format string is - # deprecated - def test_deprecated_format_string(obj, fmt_str, should_raise): - if should_raise: - self.assertRaises(TypeError, format, obj, fmt_str) - else: - format(obj, fmt_str) - - fmt_strs = ['', 's'] - + # disallowed class A: def __format__(self, fmt_str): return format('', fmt_str) - for fmt_str in fmt_strs: - test_deprecated_format_string(A(), fmt_str, False) + self.assertEqual(format(A()), '') + self.assertEqual(format(A(), ''), '') + self.assertEqual(format(A(), 's'), '') class B: pass @@ -1470,8 +1464,12 @@ pass for cls in [object, B, C]: - for fmt_str in fmt_strs: - test_deprecated_format_string(cls(), fmt_str, len(fmt_str) != 0) + obj = cls() + self.assertEqual(format(obj), str(obj)) + self.assertEqual(format(obj, ''), str(obj)) + with self.assertRaisesRegex(TypeError, + r'\b%s\b' % re.escape(cls.__name__)): + format(obj, 's') # -------------------------------------------------------------------- # make sure we can take a subclass of str as a format spec 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 @@ -1259,6 +1259,15 @@ self.assertEqual(f(b"'"), '''b"'"''') # ''' self.assertEqual(f(b"'\""), r"""b'\'"'""") # ' + @check_bytes_warnings + def test_format(self): + for b in b'abc', bytearray(b'abc'): + self.assertEqual(format(b), str(b)) + self.assertEqual(format(b, ''), str(b)) + with self.assertRaisesRegex(TypeError, + r'\b%s\b' % re.escape(type(b).__name__)): + format(b, 's') + def test_compare_bytes_to_bytearray(self): self.assertEqual(b"abc" == bytes(b"abc"), True) self.assertEqual(b"ab" != bytes(b"abc"), True) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4318,13 +4318,6 @@ "NotImplemented, the normal algorithm is used. Otherwise, it\n" "overrides the normal algorithm (and the outcome is cached).\n"); -/* - from PEP 3101, this code implements: - - class object: - def __format__(self, format_spec): - return format(str(self), format_spec) -*/ static PyObject * object_format(PyObject *self, PyObject *args) { @@ -4335,22 +4328,19 @@ if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) return NULL; + /* Issue 7994: If we're converting to a string, we + should reject format specifications */ + if (PyUnicode_GET_LENGTH(format_spec) > 0) { + PyErr_Format(PyExc_TypeError, + "unsupported format string passed to %.200s.__format__", + self->ob_type->tp_name); + return NULL; + } self_as_str = PyObject_Str(self); if (self_as_str != NULL) { - /* Issue 7994: If we're converting to a string, we - should reject format specifications */ - if (PyUnicode_GET_LENGTH(format_spec) > 0) { - PyErr_SetString(PyExc_TypeError, - "non-empty format string passed to object.__format__"); - goto done; - } - result = PyObject_Format(self_as_str, format_spec); - } - -done: - Py_XDECREF(self_as_str); - + Py_DECREF(self_as_str); + } return result; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 13:38:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 17:38:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328385=3A_An_error_message_when_non-empty_format?= =?utf-8?q?_spec_is_passed_to?= Message-ID: <20161030173844.3308.88592.4FACFECC@psf.io> https://hg.python.org/cpython/rev/6e8183abcc35 changeset: 104830:6e8183abcc35 parent: 104827:cade42bd0ee0 parent: 104829:0a985f7c6731 user: Serhiy Storchaka date: Sun Oct 30 19:38:05 2016 +0200 summary: Issue #28385: An error message when non-empty format spec is passed to object.__format__ now contains the name of actual type. files: Lib/test/test_builtin.py | 24 ++++++++++------------ Lib/test/test_bytes.py | 9 ++++++++ Objects/typeobject.c | 30 +++++++++------------------ 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -11,6 +11,7 @@ import pickle import platform import random +import re import sys import traceback import types @@ -1447,21 +1448,14 @@ # -------------------------------------------------------------------- # Issue #7994: object.__format__ with a non-empty format string is - # deprecated - def test_deprecated_format_string(obj, fmt_str, should_raise): - if should_raise: - self.assertRaises(TypeError, format, obj, fmt_str) - else: - format(obj, fmt_str) - - fmt_strs = ['', 's'] - + # disallowed class A: def __format__(self, fmt_str): return format('', fmt_str) - for fmt_str in fmt_strs: - test_deprecated_format_string(A(), fmt_str, False) + self.assertEqual(format(A()), '') + self.assertEqual(format(A(), ''), '') + self.assertEqual(format(A(), 's'), '') class B: pass @@ -1470,8 +1464,12 @@ pass for cls in [object, B, C]: - for fmt_str in fmt_strs: - test_deprecated_format_string(cls(), fmt_str, len(fmt_str) != 0) + obj = cls() + self.assertEqual(format(obj), str(obj)) + self.assertEqual(format(obj, ''), str(obj)) + with self.assertRaisesRegex(TypeError, + r'\b%s\b' % re.escape(cls.__name__)): + format(obj, 's') # -------------------------------------------------------------------- # make sure we can take a subclass of str as a format spec 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 @@ -1416,6 +1416,15 @@ self.assertEqual(f(b"'"), '''b"'"''') # ''' self.assertEqual(f(b"'\""), r"""b'\'"'""") # ' + @check_bytes_warnings + def test_format(self): + for b in b'abc', bytearray(b'abc'): + self.assertEqual(format(b), str(b)) + self.assertEqual(format(b, ''), str(b)) + with self.assertRaisesRegex(TypeError, + r'\b%s\b' % re.escape(type(b).__name__)): + format(b, 's') + def test_compare_bytes_to_bytearray(self): self.assertEqual(b"abc" == bytes(b"abc"), True) self.assertEqual(b"ab" != bytes(b"abc"), True) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4392,13 +4392,6 @@ "The default implementation does nothing. It may be\n" "overridden to extend subclasses.\n"); -/* - from PEP 3101, this code implements: - - class object: - def __format__(self, format_spec): - return format(str(self), format_spec) -*/ static PyObject * object_format(PyObject *self, PyObject *args) { @@ -4409,22 +4402,19 @@ if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) return NULL; + /* Issue 7994: If we're converting to a string, we + should reject format specifications */ + if (PyUnicode_GET_LENGTH(format_spec) > 0) { + PyErr_Format(PyExc_TypeError, + "unsupported format string passed to %.200s.__format__", + self->ob_type->tp_name); + return NULL; + } self_as_str = PyObject_Str(self); if (self_as_str != NULL) { - /* Issue 7994: If we're converting to a string, we - should reject format specifications */ - if (PyUnicode_GET_LENGTH(format_spec) > 0) { - PyErr_SetString(PyExc_TypeError, - "non-empty format string passed to object.__format__"); - goto done; - } - result = PyObject_Format(self_as_str, format_spec); - } - -done: - Py_XDECREF(self_as_str); - + Py_DECREF(self_as_str); + } return result; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 13:38:44 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 17:38:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328385=3A_An_error_message_when_non-empty_format_spec_?= =?utf-8?q?is_passed_to?= Message-ID: <20161030173844.62801.35154.F3AE4FBE@psf.io> https://hg.python.org/cpython/rev/0a985f7c6731 changeset: 104829:0a985f7c6731 branch: 3.6 parent: 104826:f1abc92a756a parent: 104828:92cae79fa5d9 user: Serhiy Storchaka date: Sun Oct 30 19:37:46 2016 +0200 summary: Issue #28385: An error message when non-empty format spec is passed to object.__format__ now contains the name of actual type. files: Lib/test/test_builtin.py | 24 ++++++++++------------ Lib/test/test_bytes.py | 9 ++++++++ Objects/typeobject.c | 30 +++++++++------------------ 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -11,6 +11,7 @@ import pickle import platform import random +import re import sys import traceback import types @@ -1447,21 +1448,14 @@ # -------------------------------------------------------------------- # Issue #7994: object.__format__ with a non-empty format string is - # deprecated - def test_deprecated_format_string(obj, fmt_str, should_raise): - if should_raise: - self.assertRaises(TypeError, format, obj, fmt_str) - else: - format(obj, fmt_str) - - fmt_strs = ['', 's'] - + # disallowed class A: def __format__(self, fmt_str): return format('', fmt_str) - for fmt_str in fmt_strs: - test_deprecated_format_string(A(), fmt_str, False) + self.assertEqual(format(A()), '') + self.assertEqual(format(A(), ''), '') + self.assertEqual(format(A(), 's'), '') class B: pass @@ -1470,8 +1464,12 @@ pass for cls in [object, B, C]: - for fmt_str in fmt_strs: - test_deprecated_format_string(cls(), fmt_str, len(fmt_str) != 0) + obj = cls() + self.assertEqual(format(obj), str(obj)) + self.assertEqual(format(obj, ''), str(obj)) + with self.assertRaisesRegex(TypeError, + r'\b%s\b' % re.escape(cls.__name__)): + format(obj, 's') # -------------------------------------------------------------------- # make sure we can take a subclass of str as a format spec 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 @@ -1416,6 +1416,15 @@ self.assertEqual(f(b"'"), '''b"'"''') # ''' self.assertEqual(f(b"'\""), r"""b'\'"'""") # ' + @check_bytes_warnings + def test_format(self): + for b in b'abc', bytearray(b'abc'): + self.assertEqual(format(b), str(b)) + self.assertEqual(format(b, ''), str(b)) + with self.assertRaisesRegex(TypeError, + r'\b%s\b' % re.escape(type(b).__name__)): + format(b, 's') + def test_compare_bytes_to_bytearray(self): self.assertEqual(b"abc" == bytes(b"abc"), True) self.assertEqual(b"ab" != bytes(b"abc"), True) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4392,13 +4392,6 @@ "The default implementation does nothing. It may be\n" "overridden to extend subclasses.\n"); -/* - from PEP 3101, this code implements: - - class object: - def __format__(self, format_spec): - return format(str(self), format_spec) -*/ static PyObject * object_format(PyObject *self, PyObject *args) { @@ -4409,22 +4402,19 @@ if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) return NULL; + /* Issue 7994: If we're converting to a string, we + should reject format specifications */ + if (PyUnicode_GET_LENGTH(format_spec) > 0) { + PyErr_Format(PyExc_TypeError, + "unsupported format string passed to %.200s.__format__", + self->ob_type->tp_name); + return NULL; + } self_as_str = PyObject_Str(self); if (self_as_str != NULL) { - /* Issue 7994: If we're converting to a string, we - should reject format specifications */ - if (PyUnicode_GET_LENGTH(format_spec) > 0) { - PyErr_SetString(PyExc_TypeError, - "non-empty format string passed to object.__format__"); - goto done; - } - result = PyObject_Format(self_as_str, format_spec); - } - -done: - Py_XDECREF(self_as_str); - + Py_DECREF(self_as_str); + } return result; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 14:59:03 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 18:59:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NDQ5?= =?utf-8?b?OiB0YXJmaWxlLm9wZW4oKSB3aXRoIG1vZGUgInIiIG9yICJyOiIgbm93IHRy?= =?utf-8?q?ies_to_open_a_tar?= Message-ID: <20161030185903.22316.46040.B6039728@psf.io> https://hg.python.org/cpython/rev/f108e063e299 changeset: 104831:f108e063e299 branch: 3.5 parent: 104828:92cae79fa5d9 user: Serhiy Storchaka date: Sun Oct 30 20:52:29 2016 +0200 summary: Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. files: Lib/tarfile.py | 4 +++- Lib/test/test_tarfile.py | 8 +++++++- Misc/NEWS | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1549,7 +1549,9 @@ if mode in ("r", "r:*"): # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: + def not_compressed(comptype): + return cls.OPEN_METH[comptype] == 'taropen' + for comptype in sorted(cls.OPEN_METH, key=not_compressed): func = getattr(cls, cls.OPEN_METH[comptype]) if fileobj is not None: saved_pos = fileobj.tell() 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 @@ -3,6 +3,7 @@ import io from hashlib import md5 from contextlib import contextmanager +from random import Random import unittest import unittest.mock @@ -349,12 +350,17 @@ def test_ignore_zeros(self): # Test TarFile's ignore_zeros option. + # generate 512 pseudorandom bytes + data = Random(0).getrandbits(512*8).to_bytes(512, 'big') for char in (b'\0', b'a'): # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a') # are ignored correctly. with self.open(tmpname, "w") as fobj: fobj.write(char * 1024) - fobj.write(tarfile.TarInfo("foo").tobuf()) + tarinfo = tarfile.TarInfo("foo") + tarinfo.size = len(data) + fobj.write(tarinfo.tobuf()) + fobj.write(data) tar = tarfile.open(tmpname, mode="r", ignore_zeros=True) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,10 @@ Library ------- +- Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar + file with compression before trying to open it without compression. Otherwise + it had 50% chance failed with ignore_zeros=True. + - Issue #23262: The webbrowser module now supports Firefox 36+ and derived browsers. Based on patch by Oleg Broytman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 14:59:04 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 18:59:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4NDQ5?= =?utf-8?b?OiB0YXJmaWxlLm9wZW4oKSB3aXRoIG1vZGUgInIiIG9yICJyOiIgbm93IHRy?= =?utf-8?q?ies_to_open_a_tar?= Message-ID: <20161030185903.25480.2439.BB005317@psf.io> https://hg.python.org/cpython/rev/e2dd0f48e643 changeset: 104832:e2dd0f48e643 branch: 2.7 parent: 104816:cf91d48aa353 user: Serhiy Storchaka date: Sun Oct 30 20:52:55 2016 +0200 summary: Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. files: Lib/tarfile.py | 4 +++- Lib/test/test_tarfile.py | 9 ++++++++- Misc/NEWS | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1665,7 +1665,9 @@ if mode in ("r", "r:*"): # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: + def not_compressed(comptype): + return cls.OPEN_METH[comptype] == 'taropen' + for comptype in sorted(cls.OPEN_METH, key=not_compressed): func = getattr(cls, cls.OPEN_METH[comptype]) if fileobj is not None: saved_pos = fileobj.tell() 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 @@ -2,7 +2,9 @@ import os import shutil import StringIO +from binascii import unhexlify from hashlib import md5 +from random import Random import errno import unittest @@ -276,12 +278,17 @@ else: _open = open + # generate 512 pseudorandom bytes + data = unhexlify('%1024x' % Random(0).getrandbits(512*8)) for char in ('\0', 'a'): # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a') # are ignored correctly. with _open(tmpname, "wb") as fobj: fobj.write(char * 1024) - fobj.write(tarfile.TarInfo("foo").tobuf()) + tarinfo = tarfile.TarInfo("foo") + tarinfo.size = len(data) + fobj.write(tarinfo.tobuf()) + fobj.write(data) tar = tarfile.open(tmpname, mode="r", ignore_zeros=True) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,10 @@ Library ------- +- Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar + file with compression before trying to open it without compression. Otherwise + it had 50% chance failed with ignore_zeros=True. + - Issue #25464: Fixed HList.header_exists() in Tix module by adding a workaround to Tix library bug. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 14:59:04 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 18:59:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzI4NDQ5OiB0YXJmaWxlLm9wZW4oKSB3aXRoIG1vZGUgInIi?= =?utf-8?q?_or_=22r=3A=22_now_tries_to_open_a_tar?= Message-ID: <20161030185904.31709.64698.C76B6FCF@psf.io> https://hg.python.org/cpython/rev/220c70519958 changeset: 104834:220c70519958 parent: 104830:6e8183abcc35 parent: 104833:de8e83262644 user: Serhiy Storchaka date: Sun Oct 30 20:58:31 2016 +0200 summary: Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. files: Lib/tarfile.py | 4 +++- Lib/test/test_tarfile.py | 8 +++++++- Misc/NEWS | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1554,7 +1554,9 @@ if mode in ("r", "r:*"): # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: + def not_compressed(comptype): + return cls.OPEN_METH[comptype] == 'taropen' + for comptype in sorted(cls.OPEN_METH, key=not_compressed): func = getattr(cls, cls.OPEN_METH[comptype]) if fileobj is not None: saved_pos = fileobj.tell() 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 @@ -3,6 +3,7 @@ import io from hashlib import md5 from contextlib import contextmanager +from random import Random import unittest import unittest.mock @@ -349,12 +350,17 @@ def test_ignore_zeros(self): # Test TarFile's ignore_zeros option. + # generate 512 pseudorandom bytes + data = Random(0).getrandbits(512*8).to_bytes(512, 'big') for char in (b'\0', b'a'): # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a') # are ignored correctly. with self.open(tmpname, "w") as fobj: fobj.write(char * 1024) - fobj.write(tarfile.TarInfo("foo").tobuf()) + tarinfo = tarfile.TarInfo("foo") + tarinfo.size = len(data) + fobj.write(tarinfo.tobuf()) + fobj.write(data) tar = tarfile.open(tmpname, mode="r", ignore_zeros=True) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,10 @@ Library ------- +- Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar + file with compression before trying to open it without compression. Otherwise + it had 50% chance failed with ignore_zeros=True. + - Issue #23262: The webbrowser module now supports Firefox 36+ and derived browsers. Based on patch by Oleg Broytman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 14:59:04 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 18:59:04 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328449=3A_tarfile=2Eopen=28=29_with_mode_=22r=22_or_?= =?utf-8?q?=22r=3A=22_now_tries_to_open_a_tar?= Message-ID: <20161030185904.35090.35181.5D7F6746@psf.io> https://hg.python.org/cpython/rev/de8e83262644 changeset: 104833:de8e83262644 branch: 3.6 parent: 104829:0a985f7c6731 parent: 104831:f108e063e299 user: Serhiy Storchaka date: Sun Oct 30 20:56:23 2016 +0200 summary: Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. files: Lib/tarfile.py | 4 +++- Lib/test/test_tarfile.py | 8 +++++++- Misc/NEWS | 5 ++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1554,7 +1554,9 @@ if mode in ("r", "r:*"): # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: + def not_compressed(comptype): + return cls.OPEN_METH[comptype] == 'taropen' + for comptype in sorted(cls.OPEN_METH, key=not_compressed): func = getattr(cls, cls.OPEN_METH[comptype]) if fileobj is not None: saved_pos = fileobj.tell() 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 @@ -3,6 +3,7 @@ import io from hashlib import md5 from contextlib import contextmanager +from random import Random import unittest import unittest.mock @@ -349,12 +350,17 @@ def test_ignore_zeros(self): # Test TarFile's ignore_zeros option. + # generate 512 pseudorandom bytes + data = Random(0).getrandbits(512*8).to_bytes(512, 'big') for char in (b'\0', b'a'): # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a') # are ignored correctly. with self.open(tmpname, "w") as fobj: fobj.write(char * 1024) - fobj.write(tarfile.TarInfo("foo").tobuf()) + tarinfo = tarfile.TarInfo("foo") + tarinfo.size = len(data) + fobj.write(tarinfo.tobuf()) + fobj.write(data) tar = tarfile.open(tmpname, mode="r", ignore_zeros=True) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,10 +27,13 @@ - Issue #28471: Fix "Python memory allocator called without holding the GIL" crash in socket.setblocking. - Library ------- +- Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar + file with compression before trying to open it without compression. Otherwise + it had 50% chance failed with ignore_zeros=True. + - Issue #23262: The webbrowser module now supports Firefox 36+ and derived browsers. Based on patch by Oleg Broytman. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 16:54:37 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 20:54:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NTQ5?= =?utf-8?q?=3A_Fixed_segfault_in_curses=27s_addch=28=29_with_ncurses6=2E?= Message-ID: <20161030205437.114791.14769.3E0A764C@psf.io> https://hg.python.org/cpython/rev/d06bf822585c changeset: 104835:d06bf822585c branch: 3.5 parent: 104831:f108e063e299 user: Serhiy Storchaka date: Sun Oct 30 22:52:06 2016 +0200 summary: Issue #28549: Fixed segfault in curses's addch() with ncurses6. files: Misc/NEWS | 2 ++ Modules/_cursesmodule.c | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,8 @@ Library ------- +- Issue #28549: Fixed segfault in curses's addch() with ncurses6. + - Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -280,7 +280,7 @@ PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj, chtype *ch #ifdef HAVE_NCURSESW - , cchar_t *wch + , wchar_t *wch #endif ) { @@ -298,8 +298,7 @@ PyUnicode_GET_LENGTH(obj)); return 0; } - memset(wch->chars, 0, sizeof(wch->chars)); - wch->chars[0] = buffer[0]; + *wch = buffer[0]; return 2; #else return PyCurses_ConvertToChtype(win, obj, ch); @@ -597,7 +596,8 @@ int type; chtype cch; #ifdef HAVE_NCURSESW - cchar_t wch; + wchar_t wstr[2]; + cchar_t wcval; #endif const char *funcname; @@ -605,14 +605,15 @@ attr = A_NORMAL; #ifdef HAVE_NCURSESW - type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, &wch); + type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, wstr); if (type == 2) { funcname = "add_wch"; - wch.attr = attr; + wstr[1] = L'\0'; + setcchar(&wcval, wstr, attr, 0, NULL); if (coordinates_group) - rtn = mvwadd_wch(cwself->win,y,x, &wch); + rtn = mvwadd_wch(cwself->win,y,x, &wcval); else { - rtn = wadd_wch(cwself->win, &wch); + rtn = wadd_wch(cwself->win, &wcval); } } else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 16:54:37 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 20:54:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328549=3A_Fixed_segfault_in_curses=27s_addch=28=29_wit?= =?utf-8?q?h_ncurses6=2E?= Message-ID: <20161030205437.30814.80077.6460E18F@psf.io> https://hg.python.org/cpython/rev/382b3d19e9fc changeset: 104836:382b3d19e9fc branch: 3.6 parent: 104833:de8e83262644 parent: 104835:d06bf822585c user: Serhiy Storchaka date: Sun Oct 30 22:53:09 2016 +0200 summary: Issue #28549: Fixed segfault in curses's addch() with ncurses6. files: Misc/NEWS | 2 ++ Modules/_cursesmodule.c | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,8 @@ Library ------- +- Issue #28549: Fixed segfault in curses's addch() with ncurses6. + - Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -280,7 +280,7 @@ PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj, chtype *ch #ifdef HAVE_NCURSESW - , cchar_t *wch + , wchar_t *wch #endif ) { @@ -298,8 +298,7 @@ PyUnicode_GET_LENGTH(obj)); return 0; } - memset(wch->chars, 0, sizeof(wch->chars)); - wch->chars[0] = buffer[0]; + *wch = buffer[0]; return 2; #else return PyCurses_ConvertToChtype(win, obj, ch); @@ -597,7 +596,8 @@ int type; chtype cch; #ifdef HAVE_NCURSESW - cchar_t wch; + wchar_t wstr[2]; + cchar_t wcval; #endif const char *funcname; @@ -605,14 +605,15 @@ attr = A_NORMAL; #ifdef HAVE_NCURSESW - type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, &wch); + type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, wstr); if (type == 2) { funcname = "add_wch"; - wch.attr = attr; + wstr[1] = L'\0'; + setcchar(&wcval, wstr, attr, 0, NULL); if (coordinates_group) - rtn = mvwadd_wch(cwself->win,y,x, &wch); + rtn = mvwadd_wch(cwself->win,y,x, &wcval); else { - rtn = wadd_wch(cwself->win, &wch); + rtn = wadd_wch(cwself->win, &wcval); } } else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 16:54:38 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 20:54:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328549=3A_Fixed_segfault_in_curses=27s_addch=28?= =?utf-8?q?=29_with_ncurses6=2E?= Message-ID: <20161030205437.45023.26388.81053FAA@psf.io> https://hg.python.org/cpython/rev/11cb97de3edd changeset: 104837:11cb97de3edd parent: 104834:220c70519958 parent: 104836:382b3d19e9fc user: Serhiy Storchaka date: Sun Oct 30 22:54:23 2016 +0200 summary: Issue #28549: Fixed segfault in curses's addch() with ncurses6. files: Misc/NEWS | 2 ++ Modules/_cursesmodule.c | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,8 @@ Library ------- +- Issue #28549: Fixed segfault in curses's addch() with ncurses6. + - Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar file with compression before trying to open it without compression. Otherwise it had 50% chance failed with ignore_zeros=True. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -280,7 +280,7 @@ PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj, chtype *ch #ifdef HAVE_NCURSESW - , cchar_t *wch + , wchar_t *wch #endif ) { @@ -298,8 +298,7 @@ PyUnicode_GET_LENGTH(obj)); return 0; } - memset(wch->chars, 0, sizeof(wch->chars)); - wch->chars[0] = buffer[0]; + *wch = buffer[0]; return 2; #else return PyCurses_ConvertToChtype(win, obj, ch); @@ -597,7 +596,8 @@ int type; chtype cch; #ifdef HAVE_NCURSESW - cchar_t wch; + wchar_t wstr[2]; + cchar_t wcval; #endif const char *funcname; @@ -605,14 +605,15 @@ attr = A_NORMAL; #ifdef HAVE_NCURSESW - type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, &wch); + type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, wstr); if (type == 2) { funcname = "add_wch"; - wch.attr = attr; + wstr[1] = L'\0'; + setcchar(&wcval, wstr, attr, 0, NULL); if (coordinates_group) - rtn = mvwadd_wch(cwself->win,y,x, &wch); + rtn = mvwadd_wch(cwself->win,y,x, &wcval); else { - rtn = wadd_wch(cwself->win, &wch); + rtn = wadd_wch(cwself->win, &wcval); } } else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 17:00:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 21:00:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328541=3A_Improve_test_coverage_for_encoding_det?= =?utf-8?q?ection_in_json_library=2E?= Message-ID: <20161030210034.3656.68371.F7A72778@psf.io> https://hg.python.org/cpython/rev/e9169a8c0692 changeset: 104839:e9169a8c0692 parent: 104837:11cb97de3edd parent: 104838:ea4cc65fc0fc user: Serhiy Storchaka date: Sun Oct 30 23:00:20 2016 +0200 summary: Issue #28541: Improve test coverage for encoding detection in json library. Original patch by Eric Appelt. files: Lib/json/__init__.py | 3 ++- Lib/test/test_json/test_unicode.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -257,7 +257,8 @@ return 'utf-16-be' if b[1] else 'utf-32-be' if not b[1]: # XX 00 00 00 - utf-32-le - # XX 00 XX XX - utf-16-le + # XX 00 00 XX - utf-16-le + # XX 00 XX -- - utf-16-le return 'utf-16-le' if b[2] or b[3] else 'utf-32-le' elif len(b) == 2: if not b[0]: diff --git a/Lib/test/test_json/test_unicode.py b/Lib/test/test_json/test_unicode.py --- a/Lib/test/test_json/test_unicode.py +++ b/Lib/test/test_json/test_unicode.py @@ -65,6 +65,19 @@ self.assertEqual(self.loads(bom + encoded), data) self.assertEqual(self.loads(encoded), data) self.assertRaises(UnicodeDecodeError, self.loads, b'["\x80"]') + # RFC-7159 and ECMA-404 extend JSON to allow documents that + # consist of only a string, which can present a special case + # not covered by the encoding detection patterns specified in + # RFC-4627 for utf-16-le (XX 00 XX 00). + self.assertEqual(self.loads('"\u2600"'.encode('utf-16-le')), + '\u2600') + # Encoding detection for small (<4) bytes objects + # is implemented as a special case. RFC-7159 and ECMA-404 + # allow single codepoint JSON documents which are only two + # bytes in utf-16 encodings w/o BOM. + self.assertEqual(self.loads(b'5\x00'), 5) + self.assertEqual(self.loads(b'\x007'), 7) + self.assertEqual(self.loads(b'57'), 57) def test_object_pairs_hook_with_unicode(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Oct 30 17:00:35 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Oct 2016 21:00:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4NTQx?= =?utf-8?q?=3A_Improve_test_coverage_for_encoding_detection_in_json_librar?= =?utf-8?q?y=2E?= Message-ID: <20161030210034.31865.41180.9705F20A@psf.io> https://hg.python.org/cpython/rev/ea4cc65fc0fc changeset: 104838:ea4cc65fc0fc branch: 3.6 parent: 104836:382b3d19e9fc user: Serhiy Storchaka date: Sun Oct 30 23:00:01 2016 +0200 summary: Issue #28541: Improve test coverage for encoding detection in json library. Original patch by Eric Appelt. files: Lib/json/__init__.py | 3 ++- Lib/test/test_json/test_unicode.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -257,7 +257,8 @@ return 'utf-16-be' if b[1] else 'utf-32-be' if not b[1]: # XX 00 00 00 - utf-32-le - # XX 00 XX XX - utf-16-le + # XX 00 00 XX - utf-16-le + # XX 00 XX -- - utf-16-le return 'utf-16-le' if b[2] or b[3] else 'utf-32-le' elif len(b) == 2: if not b[0]: diff --git a/Lib/test/test_json/test_unicode.py b/Lib/test/test_json/test_unicode.py --- a/Lib/test/test_json/test_unicode.py +++ b/Lib/test/test_json/test_unicode.py @@ -65,6 +65,19 @@ self.assertEqual(self.loads(bom + encoded), data) self.assertEqual(self.loads(encoded), data) self.assertRaises(UnicodeDecodeError, self.loads, b'["\x80"]') + # RFC-7159 and ECMA-404 extend JSON to allow documents that + # consist of only a string, which can present a special case + # not covered by the encoding detection patterns specified in + # RFC-4627 for utf-16-le (XX 00 XX 00). + self.assertEqual(self.loads('"\u2600"'.encode('utf-16-le')), + '\u2600') + # Encoding detection for small (<4) bytes objects + # is implemented as a special case. RFC-7159 and ECMA-404 + # allow single codepoint JSON documents which are only two + # bytes in utf-16 encodings w/o BOM. + self.assertEqual(self.loads(b'5\x00'), 5) + self.assertEqual(self.loads(b'\x007'), 7) + self.assertEqual(self.loads(b'57'), 57) def test_object_pairs_hook_with_unicode(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 02:13:51 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 06:13:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Update_the_f-string_test_broken_in_issue_=2328385=2E?= Message-ID: <20161031061350.17076.7510.A7BD1887@psf.io> https://hg.python.org/cpython/rev/931410a04240 changeset: 104841:931410a04240 parent: 104839:e9169a8c0692 parent: 104840:f43078ec598c user: Serhiy Storchaka date: Mon Oct 31 08:13:30 2016 +0200 summary: Update the f-string test broken in issue #28385. files: Lib/test/test_fstring.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -720,7 +720,7 @@ def test_errors(self): # see issue 26287 - self.assertAllRaise(TypeError, 'non-empty', + self.assertAllRaise(TypeError, 'unsupported', [r"f'{(lambda: 0):x}'", r"f'{(0,):x}'", ]) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 02:13:50 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 06:13:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Update_the_f-s?= =?utf-8?q?tring_test_broken_in_issue_=2328385=2E?= Message-ID: <20161031061350.17396.92222.E276C983@psf.io> https://hg.python.org/cpython/rev/f43078ec598c changeset: 104840:f43078ec598c branch: 3.6 parent: 104838:ea4cc65fc0fc user: Serhiy Storchaka date: Mon Oct 31 08:13:00 2016 +0200 summary: Update the f-string test broken in issue #28385. files: Lib/test/test_fstring.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -720,7 +720,7 @@ def test_errors(self): # see issue 26287 - self.assertAllRaise(TypeError, 'non-empty', + self.assertAllRaise(TypeError, 'unsupported', [r"f'{(lambda: 0):x}'", r"f'{(0,):x}'", ]) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 02:36:06 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 06:36:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2327517=3A_LZMA_compressor_and_decompressor_no_longer_r?= =?utf-8?q?aise_exceptions_if?= Message-ID: <20161031063606.3444.91747.13EE16DC@psf.io> https://hg.python.org/cpython/rev/fb64c7a81010 changeset: 104843:fb64c7a81010 branch: 3.6 parent: 104840:f43078ec598c parent: 104842:b06f15507978 user: Serhiy Storchaka date: Mon Oct 31 08:31:13 2016 +0200 summary: Issue #27517: LZMA compressor and decompressor no longer raise exceptions if given empty data twice. Patch by Benjamin Fogle. files: Lib/test/test_lzma.py | 38 +++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 ++ Modules/_lzmamodule.c | 5 ++++ 4 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -137,6 +137,21 @@ self.assertTrue(lzd.eof) self.assertEqual(lzd.unused_data, b"") + def test_decompressor_chunks_empty(self): + lzd = LZMADecompressor() + out = [] + for i in range(0, len(COMPRESSED_XZ), 10): + self.assertFalse(lzd.eof) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(COMPRESSED_XZ[i:i+10])) + out = b"".join(out) + self.assertEqual(out, INPUT) + self.assertEqual(lzd.check, lzma.CHECK_CRC64) + self.assertTrue(lzd.eof) + self.assertEqual(lzd.unused_data, b"") + def test_decompressor_chunks_maxsize(self): lzd = LZMADecompressor() max_length = 100 @@ -274,6 +289,16 @@ lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) self._test_decompressor(lzd, cdata, lzma.CHECK_NONE) + def test_roundtrip_raw_empty(self): + lzc = LZMACompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) + cdata = lzc.compress(INPUT) + cdata += lzc.compress(b'') + cdata += lzc.compress(b'') + cdata += lzc.compress(b'') + cdata += lzc.flush() + lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) + self._test_decompressor(lzd, cdata, lzma.CHECK_NONE) + def test_roundtrip_chunks(self): lzc = LZMACompressor() cdata = [] @@ -284,6 +309,19 @@ lzd = LZMADecompressor() self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64) + def test_roundtrip_empty_chunks(self): + lzc = LZMACompressor() + cdata = [] + for i in range(0, len(INPUT), 10): + cdata.append(lzc.compress(INPUT[i:i+10])) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.flush()) + cdata = b"".join(cdata) + lzd = LZMADecompressor() + self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64) + # LZMADecompressor intentionally does not handle concatenated streams. def test_decompressor_multistream(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -452,6 +452,7 @@ Tom Flanagan Matt Fleming Hern?n Mart?nez Foffani +Benjamin Fogle Artem Fokin Arnaud Fontaine Michael Foord diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #27517: LZMA compressor and decompressor no longer raise exceptions if + given empty data twice. Patch by Benjamin Fogle. + - Issue #28549: Fixed segfault in curses's addch() with ncurses6. - Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -521,6 +521,8 @@ Py_BEGIN_ALLOW_THREADS lzret = lzma_code(&c->lzs, action); data_size = (char *)c->lzs.next_out - PyBytes_AS_STRING(result); + if (lzret == LZMA_BUF_ERROR && len == 0 && c->lzs.avail_out > 0) + lzret = LZMA_OK; /* That wasn't a real error */ Py_END_ALLOW_THREADS if (catch_lzma_error(lzret)) goto error; @@ -896,6 +898,9 @@ PyObject *result; lzma_stream *lzs = &d->lzs; + if (lzs->avail_in == 0) + return PyBytes_FromStringAndSize(NULL, 0); + if (max_length < 0 || max_length >= INITIAL_BUFFER_SIZE) result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 02:36:06 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 06:36:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI3NTE3?= =?utf-8?q?=3A_LZMA_compressor_and_decompressor_no_longer_raise_exceptions?= =?utf-8?q?_if?= Message-ID: <20161031063606.7102.81106.EAFB19E6@psf.io> https://hg.python.org/cpython/rev/b06f15507978 changeset: 104842:b06f15507978 branch: 3.5 parent: 104835:d06bf822585c user: Serhiy Storchaka date: Mon Oct 31 08:30:09 2016 +0200 summary: Issue #27517: LZMA compressor and decompressor no longer raise exceptions if given empty data twice. Patch by Benjamin Fogle. files: Lib/test/test_lzma.py | 38 +++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 ++ Modules/_lzmamodule.c | 5 ++++ 4 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -136,6 +136,21 @@ self.assertTrue(lzd.eof) self.assertEqual(lzd.unused_data, b"") + def test_decompressor_chunks_empty(self): + lzd = LZMADecompressor() + out = [] + for i in range(0, len(COMPRESSED_XZ), 10): + self.assertFalse(lzd.eof) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(COMPRESSED_XZ[i:i+10])) + out = b"".join(out) + self.assertEqual(out, INPUT) + self.assertEqual(lzd.check, lzma.CHECK_CRC64) + self.assertTrue(lzd.eof) + self.assertEqual(lzd.unused_data, b"") + def test_decompressor_chunks_maxsize(self): lzd = LZMADecompressor() max_length = 100 @@ -273,6 +288,16 @@ lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) self._test_decompressor(lzd, cdata, lzma.CHECK_NONE) + def test_roundtrip_raw_empty(self): + lzc = LZMACompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) + cdata = lzc.compress(INPUT) + cdata += lzc.compress(b'') + cdata += lzc.compress(b'') + cdata += lzc.compress(b'') + cdata += lzc.flush() + lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) + self._test_decompressor(lzd, cdata, lzma.CHECK_NONE) + def test_roundtrip_chunks(self): lzc = LZMACompressor() cdata = [] @@ -283,6 +308,19 @@ lzd = LZMADecompressor() self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64) + def test_roundtrip_empty_chunks(self): + lzc = LZMACompressor() + cdata = [] + for i in range(0, len(INPUT), 10): + cdata.append(lzc.compress(INPUT[i:i+10])) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.flush()) + cdata = b"".join(cdata) + lzd = LZMADecompressor() + self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64) + # LZMADecompressor intentionally does not handle concatenated streams. def test_decompressor_multistream(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -446,6 +446,7 @@ Tom Flanagan Matt Fleming Hern?n Mart?nez Foffani +Benjamin Fogle Artem Fokin Arnaud Fontaine Michael Foord diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Library ------- +- Issue #27517: LZMA compressor and decompressor no longer raise exceptions if + given empty data twice. Patch by Benjamin Fogle. + - Issue #28549: Fixed segfault in curses's addch() with ncurses6. - Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -527,6 +527,8 @@ Py_BEGIN_ALLOW_THREADS lzret = lzma_code(&c->lzs, action); data_size = (char *)c->lzs.next_out - PyBytes_AS_STRING(result); + if (lzret == LZMA_BUF_ERROR && len == 0 && c->lzs.avail_out > 0) + lzret = LZMA_OK; /* That wasn't a real error */ Py_END_ALLOW_THREADS if (catch_lzma_error(lzret)) goto error; @@ -906,6 +908,9 @@ PyObject *result; lzma_stream *lzs = &d->lzs; + if (lzs->avail_in == 0) + return PyBytes_FromStringAndSize(NULL, 0); + if (max_length < 0 || max_length >= INITIAL_BUFFER_SIZE) result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 02:36:06 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 06:36:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2327517=3A_LZMA_compressor_and_decompressor_no_lo?= =?utf-8?q?nger_raise_exceptions_if?= Message-ID: <20161031063606.25435.65887.A110E092@psf.io> https://hg.python.org/cpython/rev/98c078fca8e0 changeset: 104844:98c078fca8e0 parent: 104841:931410a04240 parent: 104843:fb64c7a81010 user: Serhiy Storchaka date: Mon Oct 31 08:31:41 2016 +0200 summary: Issue #27517: LZMA compressor and decompressor no longer raise exceptions if given empty data twice. Patch by Benjamin Fogle. files: Lib/test/test_lzma.py | 38 +++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 ++ Modules/_lzmamodule.c | 5 ++++ 4 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -137,6 +137,21 @@ self.assertTrue(lzd.eof) self.assertEqual(lzd.unused_data, b"") + def test_decompressor_chunks_empty(self): + lzd = LZMADecompressor() + out = [] + for i in range(0, len(COMPRESSED_XZ), 10): + self.assertFalse(lzd.eof) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(b'')) + out.append(lzd.decompress(COMPRESSED_XZ[i:i+10])) + out = b"".join(out) + self.assertEqual(out, INPUT) + self.assertEqual(lzd.check, lzma.CHECK_CRC64) + self.assertTrue(lzd.eof) + self.assertEqual(lzd.unused_data, b"") + def test_decompressor_chunks_maxsize(self): lzd = LZMADecompressor() max_length = 100 @@ -274,6 +289,16 @@ lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) self._test_decompressor(lzd, cdata, lzma.CHECK_NONE) + def test_roundtrip_raw_empty(self): + lzc = LZMACompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) + cdata = lzc.compress(INPUT) + cdata += lzc.compress(b'') + cdata += lzc.compress(b'') + cdata += lzc.compress(b'') + cdata += lzc.flush() + lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4) + self._test_decompressor(lzd, cdata, lzma.CHECK_NONE) + def test_roundtrip_chunks(self): lzc = LZMACompressor() cdata = [] @@ -284,6 +309,19 @@ lzd = LZMADecompressor() self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64) + def test_roundtrip_empty_chunks(self): + lzc = LZMACompressor() + cdata = [] + for i in range(0, len(INPUT), 10): + cdata.append(lzc.compress(INPUT[i:i+10])) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.compress(b'')) + cdata.append(lzc.flush()) + cdata = b"".join(cdata) + lzd = LZMADecompressor() + self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64) + # LZMADecompressor intentionally does not handle concatenated streams. def test_decompressor_multistream(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -453,6 +453,7 @@ Tom Flanagan Matt Fleming Hern?n Mart?nez Foffani +Benjamin Fogle Artem Fokin Arnaud Fontaine Michael Foord diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,9 @@ Library ------- +- Issue #27517: LZMA compressor and decompressor no longer raise exceptions if + given empty data twice. Patch by Benjamin Fogle. + - Issue #28549: Fixed segfault in curses's addch() with ncurses6. - Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -521,6 +521,8 @@ Py_BEGIN_ALLOW_THREADS lzret = lzma_code(&c->lzs, action); data_size = (char *)c->lzs.next_out - PyBytes_AS_STRING(result); + if (lzret == LZMA_BUF_ERROR && len == 0 && c->lzs.avail_out > 0) + lzret = LZMA_OK; /* That wasn't a real error */ Py_END_ALLOW_THREADS if (catch_lzma_error(lzret)) goto error; @@ -896,6 +898,9 @@ PyObject *result; lzma_stream *lzs = &d->lzs; + if (lzs->avail_in == 0) + return PyBytes_FromStringAndSize(NULL, 0); + if (max_length < 0 || max_length >= INITIAL_BUFFER_SIZE) result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 04:42:41 2016 From: python-checkins at python.org (inada.naoki) Date: Mon, 31 Oct 2016 08:42:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328553=3A_Fix_logic_error_in_example_code_of_int?= =?utf-8?q?=2Eto=5Fbytes_doc=2E?= Message-ID: <20161031084230.32327.15456.C3D80877@psf.io> https://hg.python.org/cpython/rev/66f255754ce9 changeset: 104847:66f255754ce9 parent: 104844:98c078fca8e0 parent: 104846:2ae3f1599c34 user: INADA Naoki date: Mon Oct 31 17:42:25 2016 +0900 summary: Issue #28553: Fix logic error in example code of int.to_bytes doc. files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -485,7 +485,7 @@ >>> (-1024).to_bytes(10, byteorder='big', signed=True) b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00' >>> x = 1000 - >>> x.to_bytes((x.bit_length() // 8) + 1, byteorder='little') + >>> x.to_bytes((x.bit_length() + 7) // 8, byteorder='little') b'\xe8\x03' The integer is represented using *length* bytes. An :exc:`OverflowError` -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 04:42:40 2016 From: python-checkins at python.org (inada.naoki) Date: Mon, 31 Oct 2016 08:42:40 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328553=3A_Fix_logic_error_in_example_code_of_int=2Eto?= =?utf-8?q?=5Fbytes_doc=2E?= Message-ID: <20161031084230.30772.32532.B43CD44C@psf.io> https://hg.python.org/cpython/rev/2ae3f1599c34 changeset: 104846:2ae3f1599c34 branch: 3.6 parent: 104843:fb64c7a81010 parent: 104845:32d8c89e90d1 user: INADA Naoki date: Mon Oct 31 17:42:10 2016 +0900 summary: Issue #28553: Fix logic error in example code of int.to_bytes doc. files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -485,7 +485,7 @@ >>> (-1024).to_bytes(10, byteorder='big', signed=True) b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00' >>> x = 1000 - >>> x.to_bytes((x.bit_length() // 8) + 1, byteorder='little') + >>> x.to_bytes((x.bit_length() + 7) // 8, byteorder='little') b'\xe8\x03' The integer is represented using *length* bytes. An :exc:`OverflowError` -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 04:42:40 2016 From: python-checkins at python.org (inada.naoki) Date: Mon, 31 Oct 2016 08:42:40 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4NTUz?= =?utf-8?q?=3A_Fix_logic_error_in_example_code_of_int=2Eto=5Fbytes_doc=2E?= Message-ID: <20161031084230.22278.40863.7DB80892@psf.io> https://hg.python.org/cpython/rev/32d8c89e90d1 changeset: 104845:32d8c89e90d1 branch: 3.5 parent: 104842:b06f15507978 user: INADA Naoki date: Mon Oct 31 17:41:47 2016 +0900 summary: Issue #28553: Fix logic error in example code of int.to_bytes doc. files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -485,7 +485,7 @@ >>> (-1024).to_bytes(10, byteorder='big', signed=True) b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00' >>> x = 1000 - >>> x.to_bytes((x.bit_length() // 8) + 1, byteorder='little') + >>> x.to_bytes((x.bit_length() + 7) // 8, byteorder='little') b'\xe8\x03' The integer is represented using *length* bytes. An :exc:`OverflowError` -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 09:22:33 2016 From: python-checkins at python.org (eric.smith) Date: Mon, 31 Oct 2016 13:22:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_28128=3A_Print_out_b?= =?utf-8?q?etter_error/warning_messages_for_invalid_string_escapes=2E?= Message-ID: <20161031132214.17076.93253.432F1701@psf.io> https://hg.python.org/cpython/rev/259745f9a1e4 changeset: 104848:259745f9a1e4 user: Eric V. Smith date: Mon Oct 31 09:22:08 2016 -0400 summary: Issue 28128: Print out better error/warning messages for invalid string escapes. files: Include/bytesobject.h | 5 + Include/unicodeobject.h | 11 +++ Lib/test/test_string_literals.py | 27 ++++++++ Lib/test/test_unicode.py | 7 -- Misc/NEWS | 4 + Objects/bytesobject.c | 37 ++++++++++- Objects/unicodeobject.c | 38 +++++++++- Python/ast.c | 66 ++++++++++++++++++- 8 files changed, 173 insertions(+), 22 deletions(-) diff --git a/Include/bytesobject.h b/Include/bytesobject.h --- a/Include/bytesobject.h +++ b/Include/bytesobject.h @@ -74,6 +74,11 @@ PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t, const char *, Py_ssize_t, const char *); +/* Helper for PyBytes_DecodeEscape that detects invalid escape chars. */ +PyAPI_FUNC(PyObject *) _PyBytes_DecodeEscape(const char *, Py_ssize_t, + const char *, Py_ssize_t, + const char *, + const char **); /* Macro, trading safety for speed */ #ifndef Py_LIMITED_API diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1486,6 +1486,17 @@ const char *errors /* error handling */ ); +/* Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape + chars. */ +PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscape( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + const char **first_invalid_escape /* on return, points to first + invalid escaped char in + string. */ +); + PyAPI_FUNC(PyObject*) PyUnicode_AsUnicodeEscapeString( PyObject *unicode /* Unicode object */ ); diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py --- a/Lib/test/test_string_literals.py +++ b/Lib/test/test_string_literals.py @@ -31,6 +31,7 @@ import sys import shutil import tempfile +import warnings import unittest @@ -104,6 +105,19 @@ self.assertRaises(SyntaxError, eval, r""" '\U000000' """) self.assertRaises(SyntaxError, eval, r""" '\U0000000' """) + def test_eval_str_invalid_escape(self): + for b in range(1, 128): + if b in b"""\n\r"'01234567NU\\abfnrtuvx""": + continue + with self.assertWarns(DeprecationWarning): + self.assertEqual(eval(r"'\%c'" % b), '\\' + chr(b)) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=DeprecationWarning) + eval("'''\n\\z'''") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 2) + def test_eval_str_raw(self): self.assertEqual(eval(""" r'x' """), 'x') self.assertEqual(eval(r""" r'\x01' """), '\\' + 'x01') @@ -130,6 +144,19 @@ self.assertRaises(SyntaxError, eval, r""" b'\x' """) self.assertRaises(SyntaxError, eval, r""" b'\x0' """) + def test_eval_bytes_invalid_escape(self): + for b in range(1, 128): + if b in b"""\n\r"'01234567\\abfnrtvx""": + continue + with self.assertWarns(DeprecationWarning): + self.assertEqual(eval(r"b'\%c'" % b), b'\\' + bytes([b])) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=DeprecationWarning) + eval("b'''\n\\z'''") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 2) + def test_eval_bytes_raw(self): self.assertEqual(eval(""" br'x' """), b'x') self.assertEqual(eval(""" rb'x' """), b'x') 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 @@ -2413,13 +2413,6 @@ support.check_free_after_iterating(self, iter, str) support.check_free_after_iterating(self, reversed, str) - def test_invalid_sequences(self): - for letter in string.ascii_letters + "89": # 0-7 are octal escapes - if letter in "abfnrtuvxNU": - continue - with self.assertWarns(DeprecationWarning): - eval(r"'\%s'" % letter) - class CAPITest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #28128: Deprecation warning for invalid str and byte escape + sequences now prints better information about where the error + occurs. Patch by Serhiy Storchaka and Eric Smith. + - Issue #28509: dict.update() no longer allocate unnecessary large memory. - Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1105,11 +1105,12 @@ return p; } -PyObject *PyBytes_DecodeEscape(const char *s, +PyObject *_PyBytes_DecodeEscape(const char *s, Py_ssize_t len, const char *errors, Py_ssize_t unicode, - const char *recode_encoding) + const char *recode_encoding, + const char **first_invalid_escape) { int c; char *p; @@ -1123,6 +1124,8 @@ return NULL; writer.overallocate = 1; + *first_invalid_escape = NULL; + end = s + len; while (s < end) { if (*s != '\\') { @@ -1207,9 +1210,12 @@ break; default: - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "invalid escape sequence '\\%c'", *(--s)) < 0) - goto failed; + if (*first_invalid_escape == NULL) { + *first_invalid_escape = s-1; /* Back up one char, since we've + already incremented s. */ + } *p++ = '\\'; + s--; goto non_esc; /* an arbitrary number of unescaped UTF-8 bytes may follow. */ } @@ -1222,6 +1228,29 @@ return NULL; } +PyObject *PyBytes_DecodeEscape(const char *s, + Py_ssize_t len, + const char *errors, + Py_ssize_t unicode, + const char *recode_encoding) +{ + const char* first_invalid_escape; + PyObject *result = _PyBytes_DecodeEscape(s, len, errors, unicode, + recode_encoding, + &first_invalid_escape); + if (result == NULL) + return NULL; + if (first_invalid_escape != NULL) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "invalid escape sequence '\\%c'", + *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; + +} /* -------------------------------------------------------------------- */ /* object api */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5877,9 +5877,10 @@ static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; PyObject * -PyUnicode_DecodeUnicodeEscape(const char *s, - Py_ssize_t size, - const char *errors) +_PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors, + const char **first_invalid_escape) { const char *starts = s; _PyUnicodeWriter writer; @@ -5887,6 +5888,9 @@ PyObject *errorHandler = NULL; PyObject *exc = NULL; + // so we can remember if we've seen an invalid escape char or not + *first_invalid_escape = NULL; + if (size == 0) { _Py_RETURN_UNICODE_EMPTY(); } @@ -6061,9 +6065,10 @@ goto error; default: - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "invalid escape sequence '\\%c'", c) < 0) - goto onError; + if (*first_invalid_escape == NULL) { + *first_invalid_escape = s-1; /* Back up one char, since we've + already incremented s. */ + } WRITE_ASCII_CHAR('\\'); WRITE_CHAR(c); continue; @@ -6098,6 +6103,27 @@ return NULL; } +PyObject * +PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *first_invalid_escape; + PyObject *result = _PyUnicode_DecodeUnicodeEscape(s, size, errors, + &first_invalid_escape); + if (result == NULL) + return NULL; + if (first_invalid_escape != NULL) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "invalid escape sequence '\\%c'", + *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + /* Return a Unicode-Escape string version of the Unicode object. If quotes is true, the string is enclosed in u"" or u'' quotes as diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -4113,8 +4113,34 @@ return PyUnicode_DecodeUTF8(t, s - t, NULL); } +static int +warn_invalid_escape_sequence(struct compiling *c, const node *n, + char first_invalid_escape_char) +{ + PyObject *msg = PyUnicode_FromFormat("invalid escape sequence \\%c", + first_invalid_escape_char); + if (msg == NULL) { + return -1; + } + if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, + c->c_filename, LINENO(n), + NULL, NULL) < 0 && + PyErr_ExceptionMatches(PyExc_DeprecationWarning)) + { + const char *s = PyUnicode_AsUTF8(msg); + if (s != NULL) { + ast_error(c, n, s); + } + Py_DECREF(msg); + return -1; + } + Py_DECREF(msg); + return 0; +} + static PyObject * -decode_unicode_with_escapes(struct compiling *c, const char *s, size_t len) +decode_unicode_with_escapes(struct compiling *c, const node *n, const char *s, + size_t len) { PyObject *v, *u; char *buf; @@ -4167,11 +4193,41 @@ len = p - buf; s = buf; - v = PyUnicode_DecodeUnicodeEscape(s, len, NULL); + const char *first_invalid_escape; + v = _PyUnicode_DecodeUnicodeEscape(s, len, NULL, &first_invalid_escape); + + if (v != NULL && first_invalid_escape != NULL) { + if (warn_invalid_escape_sequence(c, n, *first_invalid_escape) < 0) { + /* We have not decref u before because first_invalid_escape points + inside u. */ + Py_XDECREF(u); + Py_DECREF(v); + return NULL; + } + } Py_XDECREF(u); return v; } +static PyObject * +decode_bytes_with_escapes(struct compiling *c, const node *n, const char *s, + size_t len) +{ + const char *first_invalid_escape; + PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, 0, NULL, + &first_invalid_escape); + if (result == NULL) + return NULL; + + if (first_invalid_escape != NULL) { + if (warn_invalid_escape_sequence(c, n, *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + /* Compile this expression in to an expr_ty. Add parens around the expression, in order to allow leading spaces in the expression. */ static expr_ty @@ -4310,7 +4366,7 @@ literal_end-literal_start, NULL, NULL); else - *literal = decode_unicode_with_escapes(c, literal_start, + *literal = decode_unicode_with_escapes(c, n, literal_start, literal_end-literal_start); if (!*literal) return -1; @@ -5048,12 +5104,12 @@ if (*rawmode) *result = PyBytes_FromStringAndSize(s, len); else - *result = PyBytes_DecodeEscape(s, len, NULL, /* ignored */ 0, NULL); + *result = decode_bytes_with_escapes(c, n, s, len); } else { if (*rawmode) *result = PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL); else - *result = decode_unicode_with_escapes(c, s, len); + *result = decode_unicode_with_escapes(c, n, s, len); } return *result == NULL ? -1 : 0; } -- Repository URL: https://hg.python.org/cpython From lp_benchmark_robot at intel.com Mon Oct 31 09:50:28 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 31 Oct 2016 13:50:28 +0000 Subject: [Python-checkins] NEUTRAL Benchmark Results for Python 2.7 2016-10-31 Message-ID: <469631bd-32a8-4dd7-a250-8111d4116839@irsmsx151.ger.corp.intel.com> Results for project Python 2.7, build date 2016-10-31 03:47:42 +0000 commit: e2dd0f48e643 previous commit: 8a564ab1d208 revision date: 2016-10-30 18:52:55 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v2.7.10, with hash 15c95b7d81dc from 2015-05-23 16:02:14+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.16% -0.27% 4.30% 7.77% :-) pybench 0.14% -0.09% 5.74% 4.21% :-| regex_v8 0.66% 0.21% -1.99% 10.68% :-) nbody 0.07% 0.01% 7.96% 4.02% :-) json_dump_v2 0.29% 0.05% 2.69% 10.74% :-| normal_startup 0.77% -0.53% -0.30% 2.15% :-) ssbench 0.23% -0.24% 2.14% 2.43% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/neutral-benchmark-results-for-python-2-7-2016-10-31/ Note: Benchmark results for ssbench are measured in requests/second while all other are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From lp_benchmark_robot at intel.com Mon Oct 31 09:51:09 2016 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Mon, 31 Oct 2016 13:51:09 +0000 Subject: [Python-checkins] BAD Benchmark Results for Python Default 2016-10-31 Message-ID: <8adc6f7d-ffaf-47cc-99c6-dc0fe4108007@irsmsx151.ger.corp.intel.com> Results for project Python default, build date 2016-10-31 03:01:27 +0000 commit: e9169a8c0692 previous commit: 72e64fc8746b revision date: 2016-10-30 21:00:20 +0000 environment: Haswell-EP cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB mem: 128 GB os: CentOS 7.1 kernel: Linux 3.10.0-229.4.2.el7.x86_64 Baseline results were generated using release v3.4.3, with hash b4cbecbc0781 from 2015-02-25 12:15:33+00:00 ---------------------------------------------------------------------------------- benchmark relative change since change since current rev run std_dev* last run baseline with PGO ---------------------------------------------------------------------------------- :-) django_v2 0.29% -0.28% 4.10% 16.79% :-) pybench 0.06% -0.34% 5.60% 4.78% :-( regex_v8 3.84% -2.75% -3.22% 3.50% :-) nbody 0.27% -1.17% 2.44% 4.84% :-( json_dump_v2 0.25% -0.93% -12.79% 18.06% :-| normal_startup 0.72% -0.51% 0.56% 6.64% ---------------------------------------------------------------------------------- * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/bad-benchmark-results-for-python-default-2016-10-31/ Note: Benchmark results are measured in seconds. Subject Label Legend: Attributes are determined based on the performance evolution of the workloads compared to the previous measurement iteration. NEUTRAL: performance did not change by more than 1% for any workload GOOD: performance improved by more than 1% for at least one workload and there is no regression greater than 1% BAD: performance dropped by more than 1% for at least one workload and there is no improvement greater than 1% UGLY: performance improved by more than 1% for at least one workload and also dropped by more than 1% for at least one workload Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From python-checkins at python.org Mon Oct 31 14:16:19 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 18:16:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjYu?= Message-ID: <20161031181618.34955.75950.794ED4D8@psf.io> https://hg.python.org/cpython/rev/fb672afd0151 changeset: 104850:fb672afd0151 parent: 104848:259745f9a1e4 parent: 104849:32bc59e65de4 user: Serhiy Storchaka date: Mon Oct 31 20:15:48 2016 +0200 summary: Merge from 3.6. files: Objects/dictobject.c | 123 +++++++++++++++--------------- 1 files changed, 60 insertions(+), 63 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1196,21 +1196,41 @@ } /* -Internal routine used by dictresize() to buid a hashtable of entries. +Internal routine used by dictresize() to insert an item which is +known to be absent from the dict. This routine also assumes that +the dict contains no deleted entries. Besides the performance benefit, +using insertdict() in dictresize() is dangerous (SF bug #1456209). +Note that no refcounts are changed by this routine; if needed, the caller +is responsible for incref'ing `key` and `value`. +Neither mp->ma_used nor k->dk_usable are modified by this routine; the caller +must set them correctly */ static void -build_indices(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n) +insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, + PyObject *value) { - size_t mask = (size_t)DK_SIZE(keys) - 1; - for (Py_ssize_t ix = 0; ix != n; ix++, ep++) { - Py_hash_t hash = ep->me_hash; - size_t i = hash & mask; - for (size_t perturb = hash; dk_get_index(keys, i) != DKIX_EMPTY;) { - perturb >>= PERTURB_SHIFT; - i = mask & ((i << 2) + i + perturb + 1); - } - dk_set_index(keys, i, ix); + size_t i; + PyDictKeysObject *k = mp->ma_keys; + size_t mask = (size_t)DK_SIZE(k)-1; + PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); + PyDictKeyEntry *ep; + + assert(k->dk_lookup != NULL); + assert(value != NULL); + assert(key != NULL); + assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); + i = hash & mask; + for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; + i = mask & ((i << 2) + i + perturb + 1); } + ep = &ep0[k->dk_nentries]; + assert(ep->me_value == NULL); + dk_set_index(k, i, k->dk_nentries); + k->dk_nentries++; + ep->me_key = key; + ep->me_hash = hash; + ep->me_value = value; } /* @@ -1226,10 +1246,10 @@ static int dictresize(PyDictObject *mp, Py_ssize_t minused) { - Py_ssize_t newsize, numentries; + Py_ssize_t i, newsize; PyDictKeysObject *oldkeys; PyObject **oldvalues; - PyDictKeyEntry *oldentries, *newentries; + PyDictKeyEntry *ep0; /* Find the smallest table size > minused. */ for (newsize = PyDict_MINSIZE; @@ -1240,14 +1260,8 @@ PyErr_NoMemory(); return -1; } - oldkeys = mp->ma_keys; - - /* NOTE: Current odict checks mp->ma_keys to detect resize happen. - * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. - * TODO: Try reusing oldkeys when reimplement odict. - */ - + oldvalues = mp->ma_values; /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { @@ -1256,59 +1270,42 @@ } if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; - - numentries = mp->ma_used; - oldentries = DK_ENTRIES(oldkeys); - newentries = DK_ENTRIES(mp->ma_keys); - oldvalues = mp->ma_values; + mp->ma_values = NULL; + ep0 = DK_ENTRIES(oldkeys); + /* Main loop below assumes we can transfer refcount to new keys + * and that value is stored in me_value. + * Increment ref-counts and copy values here to compensate + * This (resizing a split table) should be relatively rare */ if (oldvalues != NULL) { - /* Convert split table into new combined table. - * We must incref keys; we can transfer values. - * Note that values of split table is always dense. - */ - for (Py_ssize_t i = 0; i < numentries; i++) { - assert(oldvalues[i] != NULL); - PyDictKeyEntry *ep = &oldentries[i]; - PyObject *key = ep->me_key; - Py_INCREF(key); - newentries[i].me_key = key; - newentries[i].me_hash = ep->me_hash; - newentries[i].me_value = oldvalues[i]; + for (i = 0; i < oldkeys->dk_nentries; i++) { + if (oldvalues[i] != NULL) { + Py_INCREF(ep0[i].me_key); + ep0[i].me_value = oldvalues[i]; + } } - + } + /* Main loop */ + for (i = 0; i < oldkeys->dk_nentries; i++) { + PyDictKeyEntry *ep = &ep0[i]; + if (ep->me_value != NULL) { + insertdict_clean(mp, ep->me_key, ep->me_hash, ep->me_value); + } + } + mp->ma_keys->dk_usable -= mp->ma_used; + if (oldvalues != NULL) { + /* NULL out me_value slot in oldkeys, in case it was shared */ + for (i = 0; i < oldkeys->dk_nentries; i++) + ep0[i].me_value = NULL; DK_DECREF(oldkeys); - mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); } } - else { // combined table. - if (oldkeys->dk_nentries == numentries) { - memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); - } - else { - PyDictKeyEntry *ep = oldentries; - for (Py_ssize_t i = 0; i < numentries; i++) { - while (ep->me_value == NULL) - ep++; - newentries[i] = *ep++; - } - } - + else { assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); - if (oldkeys->dk_size == PyDict_MINSIZE && - numfreekeys < PyDict_MAXFREELIST) { - DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; - } - else { - DK_DEBUG_DECREF PyObject_FREE(oldkeys); - } + DK_DEBUG_DECREF PyObject_FREE(oldkeys); } - - build_indices(mp->ma_keys, newentries, numentries); - mp->ma_keys->dk_usable -= numentries; - mp->ma_keys->dk_nentries = numentries; return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 14:16:20 2016 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 31 Oct 2016 18:16:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E6=29=3A_Backed_out_cha?= =?utf-8?q?ngeset_6b88dfc7b25d?= Message-ID: <20161031181618.31888.8432.F0F95F46@psf.io> https://hg.python.org/cpython/rev/32bc59e65de4 changeset: 104849:32bc59e65de4 branch: 3.6 parent: 104846:2ae3f1599c34 user: Serhiy Storchaka date: Mon Oct 31 20:14:05 2016 +0200 summary: Backed out changeset 6b88dfc7b25d files: Objects/dictobject.c | 123 +++++++++++++++--------------- 1 files changed, 60 insertions(+), 63 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1195,21 +1195,41 @@ } /* -Internal routine used by dictresize() to buid a hashtable of entries. +Internal routine used by dictresize() to insert an item which is +known to be absent from the dict. This routine also assumes that +the dict contains no deleted entries. Besides the performance benefit, +using insertdict() in dictresize() is dangerous (SF bug #1456209). +Note that no refcounts are changed by this routine; if needed, the caller +is responsible for incref'ing `key` and `value`. +Neither mp->ma_used nor k->dk_usable are modified by this routine; the caller +must set them correctly */ static void -build_indices(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n) +insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, + PyObject *value) { - size_t mask = (size_t)DK_SIZE(keys) - 1; - for (Py_ssize_t ix = 0; ix != n; ix++, ep++) { - Py_hash_t hash = ep->me_hash; - size_t i = hash & mask; - for (size_t perturb = hash; dk_get_index(keys, i) != DKIX_EMPTY;) { - perturb >>= PERTURB_SHIFT; - i = mask & ((i << 2) + i + perturb + 1); - } - dk_set_index(keys, i, ix); + size_t i; + PyDictKeysObject *k = mp->ma_keys; + size_t mask = (size_t)DK_SIZE(k)-1; + PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); + PyDictKeyEntry *ep; + + assert(k->dk_lookup != NULL); + assert(value != NULL); + assert(key != NULL); + assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); + i = hash & mask; + for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; + i = mask & ((i << 2) + i + perturb + 1); } + ep = &ep0[k->dk_nentries]; + assert(ep->me_value == NULL); + dk_set_index(k, i, k->dk_nentries); + k->dk_nentries++; + ep->me_key = key; + ep->me_hash = hash; + ep->me_value = value; } /* @@ -1225,10 +1245,10 @@ static int dictresize(PyDictObject *mp, Py_ssize_t minused) { - Py_ssize_t newsize, numentries; + Py_ssize_t i, newsize; PyDictKeysObject *oldkeys; PyObject **oldvalues; - PyDictKeyEntry *oldentries, *newentries; + PyDictKeyEntry *ep0; /* Find the smallest table size > minused. */ for (newsize = PyDict_MINSIZE; @@ -1239,14 +1259,8 @@ PyErr_NoMemory(); return -1; } - oldkeys = mp->ma_keys; - - /* NOTE: Current odict checks mp->ma_keys to detect resize happen. - * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. - * TODO: Try reusing oldkeys when reimplement odict. - */ - + oldvalues = mp->ma_values; /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { @@ -1255,59 +1269,42 @@ } if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; - - numentries = mp->ma_used; - oldentries = DK_ENTRIES(oldkeys); - newentries = DK_ENTRIES(mp->ma_keys); - oldvalues = mp->ma_values; + mp->ma_values = NULL; + ep0 = DK_ENTRIES(oldkeys); + /* Main loop below assumes we can transfer refcount to new keys + * and that value is stored in me_value. + * Increment ref-counts and copy values here to compensate + * This (resizing a split table) should be relatively rare */ if (oldvalues != NULL) { - /* Convert split table into new combined table. - * We must incref keys; we can transfer values. - * Note that values of split table is always dense. - */ - for (Py_ssize_t i = 0; i < numentries; i++) { - assert(oldvalues[i] != NULL); - PyDictKeyEntry *ep = &oldentries[i]; - PyObject *key = ep->me_key; - Py_INCREF(key); - newentries[i].me_key = key; - newentries[i].me_hash = ep->me_hash; - newentries[i].me_value = oldvalues[i]; + for (i = 0; i < oldkeys->dk_nentries; i++) { + if (oldvalues[i] != NULL) { + Py_INCREF(ep0[i].me_key); + ep0[i].me_value = oldvalues[i]; + } } - + } + /* Main loop */ + for (i = 0; i < oldkeys->dk_nentries; i++) { + PyDictKeyEntry *ep = &ep0[i]; + if (ep->me_value != NULL) { + insertdict_clean(mp, ep->me_key, ep->me_hash, ep->me_value); + } + } + mp->ma_keys->dk_usable -= mp->ma_used; + if (oldvalues != NULL) { + /* NULL out me_value slot in oldkeys, in case it was shared */ + for (i = 0; i < oldkeys->dk_nentries; i++) + ep0[i].me_value = NULL; DK_DECREF(oldkeys); - mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); } } - else { // combined table. - if (oldkeys->dk_nentries == numentries) { - memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); - } - else { - PyDictKeyEntry *ep = oldentries; - for (Py_ssize_t i = 0; i < numentries; i++) { - while (ep->me_value == NULL) - ep++; - newentries[i] = *ep++; - } - } - + else { assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); - if (oldkeys->dk_size == PyDict_MINSIZE && - numfreekeys < PyDict_MAXFREELIST) { - DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; - } - else { - DK_DEBUG_DECREF PyObject_FREE(oldkeys); - } + DK_DEBUG_DECREF PyObject_FREE(oldkeys); } - - build_indices(mp->ma_keys, newentries, numentries); - mp->ma_keys->dk_usable -= numentries; - mp->ma_keys->dk_nentries = numentries; return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 14:49:09 2016 From: python-checkins at python.org (eric.smith) Date: Mon, 31 Oct 2016 18:49:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_28128=3A_Null_merge_with_3=2E6=3A_already_applied_?= =?utf-8?q?to_default=2E?= Message-ID: <20161031184909.22539.81008.202E325B@psf.io> https://hg.python.org/cpython/rev/7aa001a48120 changeset: 104852:7aa001a48120 parent: 104850:fb672afd0151 parent: 104851:ee82266ad35b user: Eric V. Smith date: Mon Oct 31 14:48:09 2016 -0400 summary: Issue 28128: Null merge with 3.6: already applied to default. files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 14:49:09 2016 From: python-checkins at python.org (eric.smith) Date: Mon, 31 Oct 2016 18:49:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgMjgxMjg6?= =?utf-8?q?_Print_out_better_error/warning_messages_for_invalid_string?= Message-ID: <20161031184909.32327.87906.E60D16E1@psf.io> https://hg.python.org/cpython/rev/ee82266ad35b changeset: 104851:ee82266ad35b branch: 3.6 parent: 104849:32bc59e65de4 user: Eric V. Smith date: Mon Oct 31 14:46:26 2016 -0400 summary: Issue 28128: Print out better error/warning messages for invalid string escapes. Backport to 3.6. files: Include/bytesobject.h | 5 + Include/unicodeobject.h | 11 +++ Lib/test/test_string_literals.py | 27 ++++++++ Lib/test/test_unicode.py | 7 -- Misc/NEWS | 4 + Objects/bytesobject.c | 37 ++++++++++- Objects/unicodeobject.c | 38 +++++++++- Python/ast.c | 66 ++++++++++++++++++- 8 files changed, 173 insertions(+), 22 deletions(-) diff --git a/Include/bytesobject.h b/Include/bytesobject.h --- a/Include/bytesobject.h +++ b/Include/bytesobject.h @@ -74,6 +74,11 @@ PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t, const char *, Py_ssize_t, const char *); +/* Helper for PyBytes_DecodeEscape that detects invalid escape chars. */ +PyAPI_FUNC(PyObject *) _PyBytes_DecodeEscape(const char *, Py_ssize_t, + const char *, Py_ssize_t, + const char *, + const char **); /* Macro, trading safety for speed */ #ifndef Py_LIMITED_API diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1486,6 +1486,17 @@ const char *errors /* error handling */ ); +/* Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape + chars. */ +PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscape( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + const char **first_invalid_escape /* on return, points to first + invalid escaped char in + string. */ +); + PyAPI_FUNC(PyObject*) PyUnicode_AsUnicodeEscapeString( PyObject *unicode /* Unicode object */ ); diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py --- a/Lib/test/test_string_literals.py +++ b/Lib/test/test_string_literals.py @@ -31,6 +31,7 @@ import sys import shutil import tempfile +import warnings import unittest @@ -104,6 +105,19 @@ self.assertRaises(SyntaxError, eval, r""" '\U000000' """) self.assertRaises(SyntaxError, eval, r""" '\U0000000' """) + def test_eval_str_invalid_escape(self): + for b in range(1, 128): + if b in b"""\n\r"'01234567NU\\abfnrtuvx""": + continue + with self.assertWarns(DeprecationWarning): + self.assertEqual(eval(r"'\%c'" % b), '\\' + chr(b)) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=DeprecationWarning) + eval("'''\n\\z'''") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 2) + def test_eval_str_raw(self): self.assertEqual(eval(""" r'x' """), 'x') self.assertEqual(eval(r""" r'\x01' """), '\\' + 'x01') @@ -130,6 +144,19 @@ self.assertRaises(SyntaxError, eval, r""" b'\x' """) self.assertRaises(SyntaxError, eval, r""" b'\x0' """) + def test_eval_bytes_invalid_escape(self): + for b in range(1, 128): + if b in b"""\n\r"'01234567\\abfnrtvx""": + continue + with self.assertWarns(DeprecationWarning): + self.assertEqual(eval(r"b'\%c'" % b), b'\\' + bytes([b])) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=DeprecationWarning) + eval("b'''\n\\z'''") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 2) + def test_eval_bytes_raw(self): self.assertEqual(eval(""" br'x' """), b'x') self.assertEqual(eval(""" rb'x' """), b'x') 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 @@ -2413,13 +2413,6 @@ support.check_free_after_iterating(self, iter, str) support.check_free_after_iterating(self, reversed, str) - def test_invalid_sequences(self): - for letter in string.ascii_letters + "89": # 0-7 are octal escapes - if letter in "abfnrtuvxNU": - continue - with self.assertWarns(DeprecationWarning): - eval(r"'\%s'" % letter) - class CAPITest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #28128: Deprecation warning for invalid str and byte escape + sequences now prints better information about where the error + occurs. Patch by Serhiy Storchaka and Eric Smith. + - Issue #28509: dict.update() no longer allocate unnecessary large memory. - Issue #28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1105,11 +1105,12 @@ return p; } -PyObject *PyBytes_DecodeEscape(const char *s, +PyObject *_PyBytes_DecodeEscape(const char *s, Py_ssize_t len, const char *errors, Py_ssize_t unicode, - const char *recode_encoding) + const char *recode_encoding, + const char **first_invalid_escape) { int c; char *p; @@ -1123,6 +1124,8 @@ return NULL; writer.overallocate = 1; + *first_invalid_escape = NULL; + end = s + len; while (s < end) { if (*s != '\\') { @@ -1207,9 +1210,12 @@ break; default: - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "invalid escape sequence '\\%c'", *(--s)) < 0) - goto failed; + if (*first_invalid_escape == NULL) { + *first_invalid_escape = s-1; /* Back up one char, since we've + already incremented s. */ + } *p++ = '\\'; + s--; goto non_esc; /* an arbitrary number of unescaped UTF-8 bytes may follow. */ } @@ -1222,6 +1228,29 @@ return NULL; } +PyObject *PyBytes_DecodeEscape(const char *s, + Py_ssize_t len, + const char *errors, + Py_ssize_t unicode, + const char *recode_encoding) +{ + const char* first_invalid_escape; + PyObject *result = _PyBytes_DecodeEscape(s, len, errors, unicode, + recode_encoding, + &first_invalid_escape); + if (result == NULL) + return NULL; + if (first_invalid_escape != NULL) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "invalid escape sequence '\\%c'", + *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; + +} /* -------------------------------------------------------------------- */ /* object api */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5896,9 +5896,10 @@ static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; PyObject * -PyUnicode_DecodeUnicodeEscape(const char *s, - Py_ssize_t size, - const char *errors) +_PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors, + const char **first_invalid_escape) { const char *starts = s; _PyUnicodeWriter writer; @@ -5906,6 +5907,9 @@ PyObject *errorHandler = NULL; PyObject *exc = NULL; + // so we can remember if we've seen an invalid escape char or not + *first_invalid_escape = NULL; + if (size == 0) { _Py_RETURN_UNICODE_EMPTY(); } @@ -6080,9 +6084,10 @@ goto error; default: - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "invalid escape sequence '\\%c'", c) < 0) - goto onError; + if (*first_invalid_escape == NULL) { + *first_invalid_escape = s-1; /* Back up one char, since we've + already incremented s. */ + } WRITE_ASCII_CHAR('\\'); WRITE_CHAR(c); continue; @@ -6117,6 +6122,27 @@ return NULL; } +PyObject * +PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *first_invalid_escape; + PyObject *result = _PyUnicode_DecodeUnicodeEscape(s, size, errors, + &first_invalid_escape); + if (result == NULL) + return NULL; + if (first_invalid_escape != NULL) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "invalid escape sequence '\\%c'", + *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + /* Return a Unicode-Escape string version of the Unicode object. If quotes is true, the string is enclosed in u"" or u'' quotes as diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -4113,8 +4113,34 @@ return PyUnicode_DecodeUTF8(t, s - t, NULL); } +static int +warn_invalid_escape_sequence(struct compiling *c, const node *n, + char first_invalid_escape_char) +{ + PyObject *msg = PyUnicode_FromFormat("invalid escape sequence \\%c", + first_invalid_escape_char); + if (msg == NULL) { + return -1; + } + if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, + c->c_filename, LINENO(n), + NULL, NULL) < 0 && + PyErr_ExceptionMatches(PyExc_DeprecationWarning)) + { + const char *s = PyUnicode_AsUTF8(msg); + if (s != NULL) { + ast_error(c, n, s); + } + Py_DECREF(msg); + return -1; + } + Py_DECREF(msg); + return 0; +} + static PyObject * -decode_unicode_with_escapes(struct compiling *c, const char *s, size_t len) +decode_unicode_with_escapes(struct compiling *c, const node *n, const char *s, + size_t len) { PyObject *v, *u; char *buf; @@ -4167,11 +4193,41 @@ len = p - buf; s = buf; - v = PyUnicode_DecodeUnicodeEscape(s, len, NULL); + const char *first_invalid_escape; + v = _PyUnicode_DecodeUnicodeEscape(s, len, NULL, &first_invalid_escape); + + if (v != NULL && first_invalid_escape != NULL) { + if (warn_invalid_escape_sequence(c, n, *first_invalid_escape) < 0) { + /* We have not decref u before because first_invalid_escape points + inside u. */ + Py_XDECREF(u); + Py_DECREF(v); + return NULL; + } + } Py_XDECREF(u); return v; } +static PyObject * +decode_bytes_with_escapes(struct compiling *c, const node *n, const char *s, + size_t len) +{ + const char *first_invalid_escape; + PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, 0, NULL, + &first_invalid_escape); + if (result == NULL) + return NULL; + + if (first_invalid_escape != NULL) { + if (warn_invalid_escape_sequence(c, n, *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + /* Compile this expression in to an expr_ty. Add parens around the expression, in order to allow leading spaces in the expression. */ static expr_ty @@ -4310,7 +4366,7 @@ literal_end-literal_start, NULL, NULL); else - *literal = decode_unicode_with_escapes(c, literal_start, + *literal = decode_unicode_with_escapes(c, n, literal_start, literal_end-literal_start); if (!*literal) return -1; @@ -5048,12 +5104,12 @@ if (*rawmode) *result = PyBytes_FromStringAndSize(s, len); else - *result = PyBytes_DecodeEscape(s, len, NULL, /* ignored */ 0, NULL); + *result = decode_bytes_with_escapes(c, n, s, len); } else { if (*rawmode) *result = PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL); else - *result = decode_unicode_with_escapes(c, s, len); + *result = decode_unicode_with_escapes(c, n, s, len); } return *result == NULL ? -1 : 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 19:37:06 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Oct 2016 23:37:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328208=3A_merge_from_3=2E6?= Message-ID: <20161031233705.31132.38815.BA535B78@psf.io> https://hg.python.org/cpython/rev/7e48e0557152 changeset: 104854:7e48e0557152 parent: 104852:7aa001a48120 parent: 104853:88e3df38d591 user: Ned Deily date: Mon Oct 31 19:36:42 2016 -0400 summary: Issue #28208: merge from 3.6 files: Mac/BuildScript/build-installer.py | 6 +++--- Misc/NEWS | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -315,9 +315,9 @@ ), ), dict( - name="SQLite 3.14.1", - url="https://www.sqlite.org/2016/sqlite-autoconf-3140100.tar.gz", - checksum='3634a90a3f49541462bcaed3474b2684', + name="SQLite 3.14.2", + url="https://www.sqlite.org/2016/sqlite-autoconf-3140200.tar.gz", + checksum='90c53cacb811db27f990b8292bd96159', extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -376,7 +376,7 @@ - Issue #28444: Fix missing extensions modules when cross compiling. -- Issue #28208: Update Windows build to use SQLite 3.14.2.0. +- Issue #28208: Update Windows build and OS X installers to use SQLite 3.14.2. - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 19:37:06 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Oct 2016 23:37:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy42KTogSXNzdWUgIzI4MDI4?= =?utf-8?q?=3A_Update_OS_X_installers_to_use_SQLite_3=2E14=2E2=2E?= Message-ID: <20161031233705.30849.53121.B49CC66E@psf.io> https://hg.python.org/cpython/rev/88e3df38d591 changeset: 104853:88e3df38d591 branch: 3.6 parent: 104851:ee82266ad35b user: Ned Deily date: Mon Oct 31 19:32:48 2016 -0400 summary: Issue #28028: Update OS X installers to use SQLite 3.14.2. Patch by Mariatta Wijaya. files: Mac/BuildScript/build-installer.py | 6 +++--- Misc/NEWS | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -315,9 +315,9 @@ ), ), dict( - name="SQLite 3.14.1", - url="https://www.sqlite.org/2016/sqlite-autoconf-3140100.tar.gz", - checksum='3634a90a3f49541462bcaed3474b2684', + name="SQLite 3.14.2", + url="https://www.sqlite.org/2016/sqlite-autoconf-3140200.tar.gz", + checksum='90c53cacb811db27f990b8292bd96159', extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -116,7 +116,7 @@ - Issue #28444: Fix missing extensions modules when cross compiling. -- Issue #28208: Update Windows build to use SQLite 3.14.2.0. +- Issue #28208: Update Windows build and OS X installers to use SQLite 3.14.2. - Issue #28248: Update Windows build to use OpenSSL 1.0.2j. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 19:59:08 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Oct 2016 23:59:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy41KTogSXNzdWUgIzI4MjQ4?= =?utf-8?q?=3A_Update_macOS_installer_build_to_use_OpenSSL_1=2E0=2E2j=2E?= Message-ID: <20161031235908.7144.91189.8FE87979@psf.io> https://hg.python.org/cpython/rev/a8799a63feb7 changeset: 104856:a8799a63feb7 branch: 3.5 parent: 104845:32d8c89e90d1 user: Ned Deily date: Mon Oct 31 19:51:58 2016 -0400 summary: Issue #28248: Update macOS installer build to use OpenSSL 1.0.2j. Original patch by Mariatta Wijaya. files: Mac/BuildScript/build-installer.py | 6 ++-- Mac/BuildScript/openssl_sdk_makedepend.patch | 12 ++++----- Misc/NEWS | 4 +-- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -242,9 +242,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2h", - url="https://www.openssl.org/source/openssl-1.0.2h.tar.gz", - checksum='9392e65072ce4b614c1392eefc1f23d0', + name="OpenSSL 1.0.2j", + url="https://www.openssl.org/source/openssl-1.0.2j.tar.gz", + checksum='96322138f0b69e61b7212bc53d5e912b', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -1,8 +1,6 @@ # HG changeset patch -# Parent d377390f787c0739a3e89f669def72d7167e5108 -# openssl_sdk_makedepend.patch # -# using openssl 1.0.2f +# using openssl 1.0.2j # # - support building with an OS X SDK @@ -11,7 +9,7 @@ diff --git a/Configure b/Configure --- a/Configure +++ b/Configure -@@ -638,12 +638,12 @@ +@@ -642,12 +642,12 @@ ##### MacOS X (a.k.a. Rhapsody or Darwin) setup "rhapsody-ppc-cc","cc:-O3 -DB_ENDIAN::(unknown):MACOSX_RHAPSODY::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}::", @@ -30,13 +28,13 @@ "debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${ppc32_asm}:osx32:dlfcn:darwin-shared:-fPIC:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", # iPhoneOS/iOS "iphoneos-cross","llvm-gcc:-O3 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fomit-frame-pointer -fno-common::-D_REENTRANT:iOS:-Wl,-search_paths_first%:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", -@@ -1717,8 +1717,7 @@ - s/^CC=.*$/CC= $cc/; +@@ -1728,8 +1728,7 @@ s/^AR=\s*ar/AR= $ar/; s/^RANLIB=.*/RANLIB= $ranlib/; + s/^RC=.*/RC= $windres/; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $cc eq "gcc"; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $ecc eq "gcc" || $ecc eq "clang"; -+ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ ++ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/; } s/^CFLAG=.*$/CFLAG= $cflags/; s/^DEPFLAG=.*$/DEPFLAG=$depflags/; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -382,8 +382,6 @@ locale encoding, and fix get_begidx() and get_endidx() to return code point indexes. -- Issue #26930: Update Windows builds to use OpenSSL 1.0.2h. - - Issue #27392: Add loop.connect_accepted_socket(). Patch by Jim Fulton. @@ -517,7 +515,7 @@ - Issue #28444: Fix missing extensions modules when cross compiling. -- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. +- Issue #28248: Update Windows build and OS X installers to use OpenSSL 1.0.2j. - Issue #28258: Fixed build with Estonian locale (python-config and distclean targets in Makefile). Patch by Arfrever Frehtes Taifersar Arahesis. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 19:59:08 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Oct 2016 23:59:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzI4MjQ4?= =?utf-8?q?=3A_Update_macOS_installer_build_to_use_OpenSSL_1=2E0=2E2j=2E?= Message-ID: <20161031235908.30882.86819.21469E0A@psf.io> https://hg.python.org/cpython/rev/33ad26897e30 changeset: 104855:33ad26897e30 branch: 2.7 parent: 104832:e2dd0f48e643 user: Ned Deily date: Mon Oct 31 19:48:38 2016 -0400 summary: Issue #28248: Update macOS installer build to use OpenSSL 1.0.2j. Original patch by Mariatta Wijaya. files: Mac/BuildScript/build-installer.py | 6 ++-- Mac/BuildScript/openssl_sdk_makedepend.patch | 12 ++++----- Misc/NEWS | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -242,9 +242,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2h", - url="https://www.openssl.org/source/openssl-1.0.2h.tar.gz", - checksum='9392e65072ce4b614c1392eefc1f23d0', + name="OpenSSL 1.0.2j", + url="https://www.openssl.org/source/openssl-1.0.2j.tar.gz", + checksum='96322138f0b69e61b7212bc53d5e912b', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -1,8 +1,6 @@ # HG changeset patch -# Parent d377390f787c0739a3e89f669def72d7167e5108 -# openssl_sdk_makedepend.patch # -# using openssl 1.0.2f +# using openssl 1.0.2j # # - support building with an OS X SDK @@ -11,7 +9,7 @@ diff --git a/Configure b/Configure --- a/Configure +++ b/Configure -@@ -638,12 +638,12 @@ +@@ -642,12 +642,12 @@ ##### MacOS X (a.k.a. Rhapsody or Darwin) setup "rhapsody-ppc-cc","cc:-O3 -DB_ENDIAN::(unknown):MACOSX_RHAPSODY::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}::", @@ -30,13 +28,13 @@ "debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${ppc32_asm}:osx32:dlfcn:darwin-shared:-fPIC:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", # iPhoneOS/iOS "iphoneos-cross","llvm-gcc:-O3 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fomit-frame-pointer -fno-common::-D_REENTRANT:iOS:-Wl,-search_paths_first%:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", -@@ -1717,8 +1717,7 @@ - s/^CC=.*$/CC= $cc/; +@@ -1728,8 +1728,7 @@ s/^AR=\s*ar/AR= $ar/; s/^RANLIB=.*/RANLIB= $ranlib/; + s/^RC=.*/RC= $windres/; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $cc eq "gcc"; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $ecc eq "gcc" || $ecc eq "clang"; -+ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ ++ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/; } s/^CFLAG=.*$/CFLAG= $cflags/; s/^DEPFLAG=.*$/DEPFLAG=$depflags/; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -249,7 +249,7 @@ Build ----- -- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. +- Issue #28248: Update Windows build and OS X installers to use OpenSSL 1.0.2j. - Issue #28258: Fixed build with Estonian locale (distclean target in Makefile). Patch by Arfrever Frehtes Taifersar Arahesis. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 19:59:08 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Oct 2016 23:59:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E6_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2328248=3A_merge_from_3=2E6?= Message-ID: <20161031235908.7195.79647.06A2C1E3@psf.io> https://hg.python.org/cpython/rev/9e66ffa7a791 changeset: 104858:9e66ffa7a791 parent: 104854:7e48e0557152 parent: 104857:c7e551f8c5d8 user: Ned Deily date: Mon Oct 31 19:58:25 2016 -0400 summary: Issue #28248: merge from 3.6 files: Mac/BuildScript/build-installer.py | 6 ++-- Mac/BuildScript/openssl_sdk_makedepend.patch | 12 ++++----- Misc/NEWS | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -213,9 +213,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2h", - url="https://www.openssl.org/source/openssl-1.0.2h.tar.gz", - checksum='9392e65072ce4b614c1392eefc1f23d0', + name="OpenSSL 1.0.2j", + url="https://www.openssl.org/source/openssl-1.0.2j.tar.gz", + checksum='96322138f0b69e61b7212bc53d5e912b', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -1,8 +1,6 @@ # HG changeset patch -# Parent d377390f787c0739a3e89f669def72d7167e5108 -# openssl_sdk_makedepend.patch # -# using openssl 1.0.2f +# using openssl 1.0.2j # # - support building with an OS X SDK @@ -11,7 +9,7 @@ diff --git a/Configure b/Configure --- a/Configure +++ b/Configure -@@ -638,12 +638,12 @@ +@@ -642,12 +642,12 @@ ##### MacOS X (a.k.a. Rhapsody or Darwin) setup "rhapsody-ppc-cc","cc:-O3 -DB_ENDIAN::(unknown):MACOSX_RHAPSODY::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}::", @@ -30,13 +28,13 @@ "debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${ppc32_asm}:osx32:dlfcn:darwin-shared:-fPIC:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", # iPhoneOS/iOS "iphoneos-cross","llvm-gcc:-O3 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fomit-frame-pointer -fno-common::-D_REENTRANT:iOS:-Wl,-search_paths_first%:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", -@@ -1717,8 +1717,7 @@ - s/^CC=.*$/CC= $cc/; +@@ -1728,8 +1728,7 @@ s/^AR=\s*ar/AR= $ar/; s/^RANLIB=.*/RANLIB= $ranlib/; + s/^RC=.*/RC= $windres/; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $cc eq "gcc"; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $ecc eq "gcc" || $ecc eq "clang"; -+ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ ++ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/; } s/^CFLAG=.*$/CFLAG= $cflags/; s/^DEPFLAG=.*$/DEPFLAG=$depflags/; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -378,7 +378,7 @@ - Issue #28208: Update Windows build and OS X installers to use SQLite 3.14.2. -- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. +- Issue #28248: Update Windows build and OS X installers to use OpenSSL 1.0.2j. - Issue #21124: Fix building the _struct module on Cygwin by passing ``NULL`` instead of ``&PyType_Type`` to PyVarObject_HEAD_INIT. Patch by Masayuki -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Oct 31 19:59:09 2016 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Oct 2016 23:59:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy41IC0+IDMuNik6?= =?utf-8?q?_Issue_=2328248=3A_merge_from_3=2E5?= Message-ID: <20161031235908.34612.67034.F103206E@psf.io> https://hg.python.org/cpython/rev/c7e551f8c5d8 changeset: 104857:c7e551f8c5d8 branch: 3.6 parent: 104853:88e3df38d591 parent: 104856:a8799a63feb7 user: Ned Deily date: Mon Oct 31 19:54:17 2016 -0400 summary: Issue #28248: merge from 3.5 files: Mac/BuildScript/build-installer.py | 6 ++-- Mac/BuildScript/openssl_sdk_makedepend.patch | 12 ++++----- Misc/NEWS | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -213,9 +213,9 @@ result.extend([ dict( - name="OpenSSL 1.0.2h", - url="https://www.openssl.org/source/openssl-1.0.2h.tar.gz", - checksum='9392e65072ce4b614c1392eefc1f23d0', + name="OpenSSL 1.0.2j", + url="https://www.openssl.org/source/openssl-1.0.2j.tar.gz", + checksum='96322138f0b69e61b7212bc53d5e912b', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Mac/BuildScript/openssl_sdk_makedepend.patch b/Mac/BuildScript/openssl_sdk_makedepend.patch --- a/Mac/BuildScript/openssl_sdk_makedepend.patch +++ b/Mac/BuildScript/openssl_sdk_makedepend.patch @@ -1,8 +1,6 @@ # HG changeset patch -# Parent d377390f787c0739a3e89f669def72d7167e5108 -# openssl_sdk_makedepend.patch # -# using openssl 1.0.2f +# using openssl 1.0.2j # # - support building with an OS X SDK @@ -11,7 +9,7 @@ diff --git a/Configure b/Configure --- a/Configure +++ b/Configure -@@ -638,12 +638,12 @@ +@@ -642,12 +642,12 @@ ##### MacOS X (a.k.a. Rhapsody or Darwin) setup "rhapsody-ppc-cc","cc:-O3 -DB_ENDIAN::(unknown):MACOSX_RHAPSODY::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}::", @@ -30,13 +28,13 @@ "debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${ppc32_asm}:osx32:dlfcn:darwin-shared:-fPIC:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", # iPhoneOS/iOS "iphoneos-cross","llvm-gcc:-O3 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fomit-frame-pointer -fno-common::-D_REENTRANT:iOS:-Wl,-search_paths_first%:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", -@@ -1717,8 +1717,7 @@ - s/^CC=.*$/CC= $cc/; +@@ -1728,8 +1728,7 @@ s/^AR=\s*ar/AR= $ar/; s/^RANLIB=.*/RANLIB= $ranlib/; + s/^RC=.*/RC= $windres/; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $cc eq "gcc"; - s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ if $ecc eq "gcc" || $ecc eq "clang"; -+ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/ ++ s/^MAKEDEPPROG=.*$/MAKEDEPPROG= $cc/; } s/^CFLAG=.*$/CFLAG= $cflags/; s/^DEPFLAG=.*$/DEPFLAG=$depflags/; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -118,7 +118,7 @@ - Issue #28208: Update Windows build and OS X installers to use SQLite 3.14.2. -- Issue #28248: Update Windows build to use OpenSSL 1.0.2j. +- Issue #28248: Update Windows build and OS X installers to use OpenSSL 1.0.2j. Tests ----- -- Repository URL: https://hg.python.org/cpython